From 62c9b1155f966cfb91d01d5598f974610962fa82 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 13 Dec 2012 18:59:10 +0400 Subject: [PATCH 01/69] listreceivedbyaddress now provides tx ids (issue #1149) --- src/rpcwallet.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 90a68f560..e17be780a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -813,6 +813,7 @@ struct tallyitem { int64 nAmount; int nConf; + vector txids; tallyitem() { nAmount = 0; @@ -854,6 +855,7 @@ Value ListReceived(const Array& params, bool fByAccounts) tallyitem& item = mapTally[address]; item.nAmount += txout.nValue; item.nConf = min(item.nConf, nDepth); + item.txids.push_back(wtx.GetHash()); } } @@ -889,6 +891,12 @@ Value ListReceived(const Array& params, bool fByAccounts) obj.push_back(Pair("account", strAccount)); obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + Array transactions; + BOOST_FOREACH(const uint256& item, (*it).second.txids) + { + transactions.push_back(item.GetHex()); + } + obj.push_back(Pair("txids", transactions)); ret.push_back(obj); } } From 1a20469428ef623f4edc2cdac72aef001836536c Mon Sep 17 00:00:00 2001 From: Andrey Date: Sun, 16 Dec 2012 23:10:32 +0400 Subject: [PATCH 02/69] Updated help and tests for getreceivedby(account|address) --- src/rpcwallet.cpp | 10 +++++++--- src/test/rpc_tests.cpp | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index e17be780a..d9d364c82 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -892,9 +892,12 @@ Value ListReceived(const Array& params, bool fByAccounts) obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); Array transactions; - BOOST_FOREACH(const uint256& item, (*it).second.txids) + if (it != mapTally.end()) { - transactions.push_back(item.GetHex()); + BOOST_FOREACH(const uint256& item, (*it).second.txids) + { + transactions.push_back(item.GetHex()); + } } obj.push_back(Pair("txids", transactions)); ret.push_back(obj); @@ -929,7 +932,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) " \"address\" : receiving address\n" " \"account\" : the account of the receiving address\n" " \"amount\" : total amount received by the address\n" - " \"confirmations\" : number of confirmations of the most recent transaction included"); + " \"confirmations\" : number of confirmations of the most recent transaction included\n" + " \"txids\" : list of transactions with outputs to the address\n"); return ListReceived(params, false); } diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index f8fe443b8..35eabed0e 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -79,6 +79,35 @@ static Value CallRPC(string args) } } +BOOST_AUTO_TEST_CASE(rpc_wallet) +{ + // Test RPC calls for various wallet statistics + Value r; + + BOOST_CHECK_NO_THROW(CallRPC("listunspent")); + BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error); + BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []")); + BOOST_CHECK(r.get_array().empty()); + + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error); + + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); + BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); +} + + BOOST_AUTO_TEST_CASE(rpc_rawparams) { // Test raw transaction API argument handling @@ -88,14 +117,6 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error); BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("listunspent")); - BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error); - BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []")); - BOOST_CHECK_THROW(r=CallRPC("listunspent 0 1 [] extra"), runtime_error); - BOOST_CHECK(r.get_array().empty()); - BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error); BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error); BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error); From 14c9d116be476d08dd18f2e9f4a8ed251a6bbf79 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 24 Mar 2013 12:59:03 -0700 Subject: [PATCH 03/69] Make explicitly requested salvage operations keep going when there is an error. In my tests corrupted wallets would often result in BDB dropping an error just due to duplicate records being found, which appears harmless. --- src/db.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 94629f3ca..907dba535 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -167,9 +167,18 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, Db db(&dbenv, 0); int result = db.verify(strFile.c_str(), NULL, &strDump, flags); - if (result != 0) + if (result == DB_VERIFY_BAD) { - printf("ERROR: db salvage failed\n"); + printf("Error: Salvage found errors, all data may not be recoverable.\n"); + if (!fAggressive) + { + printf("Error: Rerun with aggressive mode to ignore errors and continue.\n"); + return false; + } + } + if (result != 0 && result != DB_VERIFY_BAD) + { + printf("ERROR: db salvage failed: %d\n",result); return false; } From f95279ba79be1c46fe14468269ae53cdb3ac9c24 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 15 Apr 2013 16:15:11 +0200 Subject: [PATCH 04/69] fixes #2506: mac binary with proper version and copyright meta-informations (Info.plist) Due a bug in QT (https://bugreports.qt-project.org/browse/QTBUG-21267), the mac binary of the last release contains bulk meta informations. The url-handler (bitcoin://) is also not working in current release Should be fixed with this commit. Signed-off-by: Jonas Schnelli --- doc/release-process.txt | 1 + share/qt/Info.plist | 6 +++++- share/qt/clean_mac_info_plist.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100755 share/qt/clean_mac_info_plist.py diff --git a/doc/release-process.txt b/doc/release-process.txt index 29271ad22..ce6614335 100644 --- a/doc/release-process.txt +++ b/doc/release-process.txt @@ -80,6 +80,7 @@ make export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) + python2.7 share/qt/clean_mac_info_plist.py python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist Build output expected: diff --git a/share/qt/Info.plist b/share/qt/Info.plist index 58b2152e9..2312094c4 100644 --- a/share/qt/Info.plist +++ b/share/qt/Info.plist @@ -7,7 +7,11 @@ CFBundlePackageType APPL CFBundleGetInfoString - Bitcoin-Qt + $VERSION, Copyright © 2009-$YEAR The Bitcoin developers + CFBundleShortVersionString + $VERSION + CFBundleVersion + $VERSION CFBundleSignature ???? CFBundleExecutable diff --git a/share/qt/clean_mac_info_plist.py b/share/qt/clean_mac_info_plist.py new file mode 100755 index 000000000..df677f50b --- /dev/null +++ b/share/qt/clean_mac_info_plist.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Jonas Schnelli, 2013 +# make sure the Bitcoin-Qt.app contains the right plist (including the right version) +# fix made because of serval bugs in Qt mac deployment (https://bugreports.qt-project.org/browse/QTBUG-21267) + +from string import Template +from datetime import date + +bitcoinDir = "./"; + +inFile = bitcoinDir+"/share/qt/Info.plist" +outFile = "Bitcoin-Qt.app/Contents/Info.plist" +version = "unknown"; + +fileForGrabbingVersion = bitcoinDir+"bitcoin-qt.pro" +for line in open(fileForGrabbingVersion): + lineArr = line.replace(" ", "").split("="); + if lineArr[0].startswith("VERSION"): + version = lineArr[1].replace("\n", ""); + +fIn = open(inFile, "r") +fileContent = fIn.read() +s = Template(fileContent) +newFileContent = s.substitute(VERSION=version,YEAR=date.today().year) + +fOut = open(outFile, "w"); +fOut.write(newFileContent); + +print "Info.plist fresh created" \ No newline at end of file From 61032f894247f7a4158ec5b41067bcd7c3f35910 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Tue, 23 Apr 2013 09:54:29 +0200 Subject: [PATCH 05/69] remove obsolete and unused typedef for Windows --- src/util.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util.h b/src/util.h index 0641c4be7..c940686c2 100644 --- a/src/util.h +++ b/src/util.h @@ -11,8 +11,6 @@ #include #include #include -#else -typedef int pid_t; /* define for Windows compatibility */ #endif #include #include From e79110822efdc5fef27b1b24232a0655359e7df3 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sat, 23 Feb 2013 23:51:02 +0100 Subject: [PATCH 06/69] remove duplicate bitdb.Open() code from init - remove code from step 7, which we already have in step 5 of init --- src/init.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f6485c3b1..11b7554ed 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -733,15 +733,6 @@ bool AppInit2(boost::thread_group& threadGroup) fReindex = GetBoolArg("-reindex"); - // Todo: Check if needed, because in step 5 we do the same - if (!bitdb.Open(GetDataDir())) - { - string msg = strprintf(_("Error initializing database environment %s!" - " To recover, BACKUP THAT DIRECTORY, then remove" - " everything from it except for wallet.dat."), strDataDir.c_str()); - return InitError(msg); - } - // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/ filesystem::path blocksDir = GetDataDir() / "blocks"; if (!filesystem::exists(blocksDir)) From 1859aafef0a273e27e886646e36140cc5e375ee1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 24 Apr 2013 00:41:04 +0200 Subject: [PATCH 07/69] Try moving database/ away in case of failure --- src/init.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 11b7554ed..48495c446 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -605,8 +605,22 @@ bool AppInit2(boost::thread_group& threadGroup) if (!bitdb.Open(GetDataDir())) { - string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir.c_str()); - return InitError(msg); + // try moving the database env out of the way + boost::filesystem::path pathDatabase = GetDataDir() / "database"; + boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%"PRI64d".bak", GetTime()); + try { + boost::filesystem::rename(pathDatabase, pathDatabaseBak); + printf("Moved old %s to %s. Retrying.\n", pathDatabase.string().c_str(), pathDatabaseBak.string().c_str()); + } catch(boost::filesystem::filesystem_error &error) { + // failure is ok (well, not really, but it's not worse than what we started with) + } + + // try again + if (!bitdb.Open(GetDataDir())) { + // if it still fails, it probably means we can't even create the database env + string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir.c_str()); + return InitError(msg); + } } if (GetBoolArg("-salvagewallet")) From ccda03b57022369c4352d0f5a816cff9ace833e6 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 24 Apr 2013 00:43:14 +0200 Subject: [PATCH 08/69] Remove database/ after clean shutdown --- src/db.cpp | 10 ++++++---- src/db.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 35d6cca89..52d613bc3 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -38,7 +38,7 @@ void CDBEnv::EnvShutdown() if (ret != 0) printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret); if (!fMockDb) - DbEnv(0).remove(strPath.c_str(), 0); + DbEnv(0).remove(path.string().c_str(), 0); } CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) @@ -57,14 +57,14 @@ void CDBEnv::Close() EnvShutdown(); } -bool CDBEnv::Open(const boost::filesystem::path& path) +bool CDBEnv::Open(const boost::filesystem::path& pathIn) { if (fDbEnvInit) return true; boost::this_thread::interruption_point(); - strPath = path.string(); + path = pathIn; filesystem::path pathLogDir = path / "database"; filesystem::create_directory(pathLogDir); filesystem::path pathErrorFile = path / "db.log"; @@ -84,7 +84,7 @@ bool CDBEnv::Open(const boost::filesystem::path& path) dbenv.set_flags(DB_AUTO_COMMIT, 1); dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv.open(strPath.c_str(), + int ret = dbenv.open(path.string().c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -456,6 +456,8 @@ void CDBEnv::Flush(bool fShutdown) { dbenv.log_archive(&listp, DB_ARCH_REMOVE); Close(); + if (!fMockDb) + boost::filesystem::remove_all(path / "database"); } } } diff --git a/src/db.h b/src/db.h index 206da91e9..ea440c496 100644 --- a/src/db.h +++ b/src/db.h @@ -33,7 +33,7 @@ class CDBEnv private: bool fDbEnvInit; bool fMockDb; - std::string strPath; + boost::filesystem::path path; void EnvShutdown(); From 360cfe142c552ac5c4d904a1e970390188151ca8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 25 Apr 2013 19:30:28 +0200 Subject: [PATCH 09/69] Allow the default key to be unavailable This solves the issue where no default key can be added after -salvagewallet. --- src/init.cpp | 10 +++++----- src/main.cpp | 5 ++++- src/wallet.cpp | 39 ++++++++++++++++++++++----------------- src/wallet.h | 2 +- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f6485c3b1..f35979bc0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -939,11 +939,11 @@ bool AppInit2(boost::thread_group& threadGroup) RandAddSeedPerfmon(); CPubKey newDefaultKey; - if (!pwalletMain->GetKeyFromPool(newDefaultKey, false)) - strErrors << _("Cannot initialize keypool") << "\n"; - pwalletMain->SetDefaultKey(newDefaultKey); - if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) - strErrors << _("Cannot write default address") << "\n"; + if (pwalletMain->GetKeyFromPool(newDefaultKey, false)) { + pwalletMain->SetDefaultKey(newDefaultKey); + if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) + strErrors << _("Cannot write default address") << "\n"; + } } printf("%s", strErrors.str().c_str()); diff --git a/src/main.cpp b/src/main.cpp index aace382d8..45fb7af00 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4158,7 +4158,10 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vout.resize(1); - txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; + CPubKey pubkey; + if (!reservekey.GetReservedKey(pubkey)) + return NULL; + txNew.vout[0].scriptPubKey << pubkey << OP_CHECKSIG; // Add our coinbase tx as first transaction pblock->vtx.push_back(txNew); diff --git a/src/wallet.cpp b/src/wallet.cpp index c7eb4f74e..0672a3669 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -457,17 +457,19 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) return false; #ifndef QT_GUI // If default receiving address gets used, replace it with a new one - CScript scriptDefaultKey; - scriptDefaultKey.SetDestination(vchDefaultKey.GetID()); - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - { - if (txout.scriptPubKey == scriptDefaultKey) + if (vchDefaultKey.IsValid()) { + CScript scriptDefaultKey; + scriptDefaultKey.SetDestination(vchDefaultKey.GetID()); + BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - CPubKey newDefaultKey; - if (GetKeyFromPool(newDefaultKey, false)) + if (txout.scriptPubKey == scriptDefaultKey) { - SetDefaultKey(newDefaultKey); - SetAddressBookName(vchDefaultKey.GetID(), ""); + CPubKey newDefaultKey; + if (GetKeyFromPool(newDefaultKey, false)) + { + SetDefaultKey(newDefaultKey); + SetAddressBookName(vchDefaultKey.GetID(), ""); + } } } } @@ -1199,8 +1201,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW // post-backup change. // Reserve a new key pair from key pool - CPubKey vchPubKey = reservekey.GetReservedKey(); - // assert(mapKeys.count(vchPubKey)); + CPubKey vchPubKey; + assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked // Fill a vout to ourself // TODO: pass in scriptChange instead of reservekey so @@ -1737,7 +1739,7 @@ set< set > CWallet::GetAddressGroupings() return ret; } -CPubKey CReserveKey::GetReservedKey() +bool CReserveKey::GetReservedKey(CPubKey& pubkey) { if (nIndex == -1) { @@ -1745,14 +1747,17 @@ CPubKey CReserveKey::GetReservedKey() pwallet->ReserveKeyFromKeyPool(nIndex, keypool); if (nIndex != -1) vchPubKey = keypool.vchPubKey; - else - { - printf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!"); - vchPubKey = pwallet->vchDefaultKey; + else { + if (pwallet->vchDefaultKey.IsValid()) { + printf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!"); + vchPubKey = pwallet->vchDefaultKey; + } else + return false; } } assert(vchPubKey.IsValid()); - return vchPubKey; + pubkey = vchPubKey; + return true; } void CReserveKey::KeepKey() diff --git a/src/wallet.h b/src/wallet.h index 2e007557b..55200476a 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -331,7 +331,7 @@ public: } void ReturnKey(); - CPubKey GetReservedKey(); + bool GetReservedKey(CPubKey &pubkey); void KeepKey(); }; From 9f4976afe2568a6dd4a4026292e91697bedda4b6 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 1 May 2013 10:41:24 -0400 Subject: [PATCH 10/69] RPC: strictly require HTTP URI "/" Previously, JSON-RPC clients accessed URI "/", and the JSON-RPC server did not care about the URI at all, and would accept any URI as valid. Change the JSON-RPC server to require URI "/" for all current accesses. This changes enables the addition of future interfaces at different URIs, such as pull request #1982 which demonstrates HTTP REST wallet download. Or, a future, breaking change in JSON-RPC interface could be introduced by serving JSON-RPC calls from new URI "/v2/". --- src/bitcoinrpc.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 9c126fc3d..a9b73fd5a 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -940,6 +940,11 @@ void ServiceConnection(AcceptedConnection *conn) // Read HTTP message headers and body ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto); + if (strURI != "/") { + conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; + break; + } + // Check authorization if (mapHeaders.count("authorization") == 0) { From e31aa7c9d7dd204b5658f20c19565eee308e35c1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 1 May 2013 16:23:27 +0200 Subject: [PATCH 11/69] Improve gettxoutsetinfo command * Bugfix: output the correct best block hash (during IBD, it can differ from the actual current best block) * Add height to output * Add hash_serialized, which is a hash of the entire UTXO state. Can be useful to compare two nodes. * Add total_amount, the sum of all UTXOs' values. --- src/main.h | 5 ++++- src/rpcblockchain.cpp | 5 ++++- src/txdb.cpp | 22 +++++++++++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main.h b/src/main.h index 24b2cb2aa..e02edbc52 100644 --- a/src/main.h +++ b/src/main.h @@ -2096,11 +2096,14 @@ extern CTxMemPool mempool; struct CCoinsStats { int nHeight; + uint256 hashBlock; uint64 nTransactions; uint64 nTransactionOutputs; uint64 nSerializedSize; + uint256 hashSerialized; + int64 nTotalAmount; - CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {} + CCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0), nTotalAmount(0) {} }; /** Abstract view on the open txout dataset. */ diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 220067905..11af1abf5 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -172,10 +172,13 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) CCoinsStats stats; if (pcoinsTip->GetStats(stats)) { - ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex())); + ret.push_back(Pair("height", (boost::int64_t)stats.nHeight)); + ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions)); ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs)); ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize)); + ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex())); + ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); } return ret; } diff --git a/src/txdb.cpp b/src/txdb.cpp index 5b0527c76..3d34710d2 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -5,6 +5,7 @@ #include "txdb.h" #include "main.h" +#include "hash.h" using namespace std; @@ -114,6 +115,10 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) { leveldb::Iterator *pcursor = db.NewIterator(); pcursor->SeekToFirst(); + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + stats.hashBlock = GetBestBlock()->GetBlockHash(); + ss << stats.hashBlock; + int64 nTotalAmount = 0; while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { @@ -128,13 +133,22 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) { ssValue >> coins; uint256 txhash; ssKey >> txhash; - + ss << txhash; + ss << VARINT(coins.nVersion); + ss << (coins.fCoinBase ? 'c' : 'n'); + ss << VARINT(coins.nHeight); stats.nTransactions++; - BOOST_FOREACH(const CTxOut &out, coins.vout) { - if (!out.IsNull()) + for (unsigned int i=0; iNext(); } catch (std::exception &e) { @@ -143,6 +157,8 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) { } delete pcursor; stats.nHeight = GetBestBlock()->nHeight; + stats.hashSerialized = ss.GetHash(); + stats.nTotalAmount = nTotalAmount; return true; } From 2aceeb01a9b0b0c6bfa0d56211453e87bc33d6e4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 1 May 2013 19:09:04 +0200 Subject: [PATCH 12/69] Bugfix: if no bestblock record is present, do a -rescan It is possible to have a wallet.dat file without any bestblock record at all (if created offline, for example), which - when loaded into a client with a up-to-date chain - does no rescan and shows no transactions. Also make sure to write the current best block after a rescan, so it isn't necessary twice. --- src/init.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 3845cfad8..3c1040a79 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -988,6 +988,8 @@ bool AppInit2(boost::thread_group& threadGroup) CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) pindexRescan = locator.GetBlockIndex(); + else + pindexRescan = pindexGenesisBlock; } if (pindexBest && pindexBest != pindexRescan) { @@ -996,6 +998,8 @@ bool AppInit2(boost::thread_group& threadGroup) nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); + nWalletDBUpdated++; } // ********************************************************* Step 9: import blocks From a9d9f0f5f72ab1f9ebc2f76bfe3b7921fa2826d7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 30 Apr 2013 18:42:01 +0200 Subject: [PATCH 13/69] Do not kill connections on recv buffer overflow Instead of killing a connection when the receive buffer overflows, just temporarily halt receiving before that happens. Also, no matter what, always allow at least one full message in the receive buffer (otherwise blocks larger than the configured buffer size would pause indefinitely). --- src/net.cpp | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 3fa48ae48..54ed1d9b5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -841,19 +841,39 @@ void ThreadSocketHandler() { if (pnode->hSocket == INVALID_SOCKET) continue; + FD_SET(pnode->hSocket, &fdsetError); + hSocketMax = max(hSocketMax, pnode->hSocket); + have_fds = true; + + // Implement the following logic: + // * If there is data to send, select() for sending data. As this only + // happens when optimistic write failed, we choose to first drain the + // write buffer in this case before receiving more. This avoids + // needlessly queueing received data, if the remote peer is not themselves + // receiving data. This means properly utilizing TCP flow control signalling. + // * Otherwise, if there is no (complete) message in the receive buffer, + // or there is space left in the buffer, select() for receiving data. + // * (if neither of the above applies, there is certainly one message + // in the receiver buffer ready to be processed). + // Together, that means that at least one of the following is always possible, + // so we don't deadlock: + // * We send some data. + // * We wait for data to be received (and disconnect after timeout). + // * We process a message in the buffer (message handler thread). { TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) { - // do not read, if draining write queue - if (!pnode->vSendMsg.empty()) - FD_SET(pnode->hSocket, &fdsetSend); - else - FD_SET(pnode->hSocket, &fdsetRecv); - FD_SET(pnode->hSocket, &fdsetError); - hSocketMax = max(hSocketMax, pnode->hSocket); - have_fds = true; + if (lockSend && !pnode->vSendMsg.empty()) { + FD_SET(pnode->hSocket, &fdsetSend); + continue; } } + { + TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); + if (lockRecv && ( + pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || + pnode->GetTotalRecvSize() <= ReceiveFloodSize())) + FD_SET(pnode->hSocket, &fdsetRecv); + } } } @@ -959,12 +979,7 @@ void ThreadSocketHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - if (pnode->GetTotalRecvSize() > ReceiveFloodSize()) { - if (!pnode->fDisconnect) - printf("socket recv flood control disconnect (%u bytes)\n", pnode->GetTotalRecvSize()); - pnode->CloseSocketDisconnect(); - } - else { + { // typical socket buffer is 8K-64K char pchBuf[0x10000]; int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); From d605bc4cd13716fde9c34d79a01f4ee128f8814f Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 2 May 2013 12:26:33 -0400 Subject: [PATCH 14/69] Exit cleanly if AppInit2 returns false Bitcoin-Qt could core dump if application initialization failed in certain ways. I double-fixed this: 1) qt/bitcoin.cpp now shuts down core threads cleanly if AppInit2 returns false 2) init.cpp now exits before StartNode() if strErrors is set (no reason to StartNode if we're just going to exit immediately anyway). Tested by triggering all of the various ways AppInit2 can fail, either by passing bogus command-line arguments or just recompiling tweaked code to simulate failure. This is a partial fix for #2480 --- src/init.cpp | 6 +++--- src/qt/bitcoin.cpp | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3845cfad8..c2259f1d7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1033,6 +1033,9 @@ bool AppInit2(boost::thread_group& threadGroup) if (!CheckDiskSpace()) return false; + if (!strErrors.str().empty()) + return InitError(strErrors.str()); + RandAddSeedPerfmon(); //// debug print @@ -1054,9 +1057,6 @@ bool AppInit2(boost::thread_group& threadGroup) uiInterface.InitMessage(_("Done loading")); - if (!strErrors.str().empty()) - return InitError(strErrors.str()); - // Add wallet transactions that aren't already in a block to mapTransactions pwalletMain->ReacceptWalletTransactions(); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 25448ea8c..a567eafd5 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -271,6 +271,9 @@ int main(int argc, char *argv[]) } else { + threadGroup.interrupt_all(); + threadGroup.join_all(); + Shutdown(); return 1; } } catch (std::exception& e) { From 2f15e86a68aba56a8ea8e01e58b2fb7b71846b51 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 2 May 2013 12:43:07 -0400 Subject: [PATCH 15/69] Do not write to wallet during LoadWallet When debugging another issue, I found a hang-during-startup race condition due to LoadWallet calling SetMinVersion (via LoadCryptedKey). Writing to the file that you're in the process of reading is a bad idea. --- src/wallet.cpp | 5 +++++ src/wallet.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wallet.cpp b/src/wallet.cpp index c7eb4f74e..9658dab67 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -71,6 +71,11 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector &vchCryptedSecret) +{ + return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); +} + bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) diff --git a/src/wallet.h b/src/wallet.h index 2e007557b..348f36a0e 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -145,7 +145,7 @@ public: // Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } + bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); bool AddCScript(const CScript& redeemScript); bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); } From b357a71cfaf99dd2e7d203a12edfcc5df4a93386 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 2 May 2013 18:55:25 +0200 Subject: [PATCH 16/69] clear path cache after getting a proper config file (fixes #2605) Signed-off-by: Jonas Schnelli --- src/util.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/util.cpp b/src/util.cpp index 8b6d8b32c..4c9b897f5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -83,6 +83,7 @@ bool fNoListen = false; bool fLogTimestamps = false; CMedianFilter vTimeOffsets(200,0); volatile bool fReopenDebugLog = false; +bool fCachedPath[2] = {false, false}; // Init OpenSSL library multithreading support static CCriticalSection** ppmutexOpenSSL; @@ -1048,13 +1049,12 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) static fs::path pathCached[2]; static CCriticalSection csPathCached; - static bool cachedPath[2] = {false, false}; fs::path &path = pathCached[fNetSpecific]; // This can be called during exceptions by printf, so we cache the // value so we don't have to do memory allocations after that. - if (cachedPath[fNetSpecific]) + if (fCachedPath[fNetSpecific]) return path; LOCK(csPathCached); @@ -1073,7 +1073,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) fs::create_directory(path); - cachedPath[fNetSpecific] = true; + fCachedPath[fNetSpecific] = true; return path; } @@ -1091,6 +1091,9 @@ void ReadConfigFile(map& mapSettingsRet, if (!streamConfig.good()) return; // No bitcoin.conf file is OK + // clear path cache after loading config file + fCachedPath[0] = fCachedPath[1] = false; + set setOptions; setOptions.insert("*"); From bce697d7faef0d8119ba80ae583cfcce460c7f81 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 2 May 2013 16:16:03 -0400 Subject: [PATCH 17/69] Remove implementation of disabled opcodes So we stop getting pull requests (like #2604) fixing problems with disabled Script opcodes. A hard fork would be required to re-enable these, and if we ever did that we'd require extensive review and testing. --- src/script.cpp | 167 +------------------------------------------------ 1 file changed, 1 insertion(+), 166 deletions(-) diff --git a/src/script.cpp b/src/script.cpp index 5e5cd096c..90066efd3 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -54,32 +54,6 @@ bool CastToBool(const valtype& vch) return false; } -// -// WARNING: This does not work as expected for signed integers; the sign-bit -// is left in place as the integer is zero-extended. The correct behavior -// would be to move the most significant bit of the last byte during the -// resize process. MakeSameSize() is currently only used by the disabled -// opcodes OP_AND, OP_OR, and OP_XOR. -// -void MakeSameSize(valtype& vch1, valtype& vch2) -{ - // Lengthen the shorter one - if (vch1.size() < vch2.size()) - // PATCH: - // +unsigned char msb = vch1[vch1.size()-1]; - // +vch1[vch1.size()-1] &= 0x7f; - // vch1.resize(vch2.size(), 0); - // +vch1[vch1.size()-1] = msb; - vch1.resize(vch2.size(), 0); - if (vch2.size() < vch1.size()) - // PATCH: - // +unsigned char msb = vch2[vch2.size()-1]; - // +vch2[vch2.size()-1] &= 0x7f; - // vch2.resize(vch1.size(), 0); - // +vch2[vch2.size()-1] = msb; - vch2.resize(vch1.size(), 0); -} - // @@ -361,7 +335,7 @@ bool EvalScript(vector >& stack, const CScript& script, co opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) - return false; + return false; // Disabled opcodes. if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); @@ -659,64 +633,6 @@ bool EvalScript(vector >& stack, const CScript& script, co break; - // - // Splice ops - // - case OP_CAT: - { - // (x1 x2 -- out) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - vch1.insert(vch1.end(), vch2.begin(), vch2.end()); - popstack(stack); - if (stacktop(-1).size() > MAX_SCRIPT_ELEMENT_SIZE) - return false; - } - break; - - case OP_SUBSTR: - { - // (in begin size -- out) - if (stack.size() < 3) - return false; - valtype& vch = stacktop(-3); - int nBegin = CastToBigNum(stacktop(-2)).getint(); - int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); - if (nBegin < 0 || nEnd < nBegin) - return false; - if (nBegin > (int)vch.size()) - nBegin = vch.size(); - if (nEnd > (int)vch.size()) - nEnd = vch.size(); - vch.erase(vch.begin() + nEnd, vch.end()); - vch.erase(vch.begin(), vch.begin() + nBegin); - popstack(stack); - popstack(stack); - } - break; - - case OP_LEFT: - case OP_RIGHT: - { - // (in size -- out) - if (stack.size() < 2) - return false; - valtype& vch = stacktop(-2); - int nSize = CastToBigNum(stacktop(-1)).getint(); - if (nSize < 0) - return false; - if (nSize > (int)vch.size()) - nSize = vch.size(); - if (opcode == OP_LEFT) - vch.erase(vch.begin() + nSize, vch.end()); - else - vch.erase(vch.begin(), vch.end() - nSize); - popstack(stack); - } - break; - case OP_SIZE: { // (in -- in size) @@ -731,51 +647,6 @@ bool EvalScript(vector >& stack, const CScript& script, co // // Bitwise logic // - case OP_INVERT: - { - // (in - out) - if (stack.size() < 1) - return false; - valtype& vch = stacktop(-1); - for (unsigned int i = 0; i < vch.size(); i++) - vch[i] = ~vch[i]; - } - break; - - // - // WARNING: These disabled opcodes exhibit unexpected behavior - // when used on signed integers due to a bug in MakeSameSize() - // [see definition of MakeSameSize() above]. - // - case OP_AND: - case OP_OR: - case OP_XOR: - { - // (x1 x2 - out) - if (stack.size() < 2) - return false; - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - MakeSameSize(vch1, vch2); // <-- NOT SAFE FOR SIGNED VALUES - if (opcode == OP_AND) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] &= vch2[i]; - } - else if (opcode == OP_OR) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] |= vch2[i]; - } - else if (opcode == OP_XOR) - { - for (unsigned int i = 0; i < vch1.size(); i++) - vch1[i] ^= vch2[i]; - } - popstack(stack); - } - break; - case OP_EQUAL: case OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL @@ -810,8 +681,6 @@ bool EvalScript(vector >& stack, const CScript& script, co // case OP_1ADD: case OP_1SUB: - case OP_2MUL: - case OP_2DIV: case OP_NEGATE: case OP_ABS: case OP_NOT: @@ -825,8 +694,6 @@ bool EvalScript(vector >& stack, const CScript& script, co { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; - case OP_2MUL: bn <<= 1; break; - case OP_2DIV: bn >>= 1; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; @@ -840,11 +707,6 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_ADD: case OP_SUB: - case OP_MUL: - case OP_DIV: - case OP_MOD: - case OP_LSHIFT: - case OP_RSHIFT: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: @@ -873,33 +735,6 @@ bool EvalScript(vector >& stack, const CScript& script, co bn = bn1 - bn2; break; - case OP_MUL: - if (!BN_mul(&bn, &bn1, &bn2, pctx)) - return false; - break; - - case OP_DIV: - if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) - return false; - break; - - case OP_MOD: - if (!BN_mod(&bn, &bn1, &bn2, pctx)) - return false; - break; - - case OP_LSHIFT: - if (bn2 < bnZero || bn2 > CBigNum(2048)) - return false; - bn = bn1 << bn2.getulong(); - break; - - case OP_RSHIFT: - if (bn2 < bnZero || bn2 > CBigNum(2048)) - return false; - bn = bn1 >> bn2.getulong(); - break; - case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; From 367491df9d4a4e323a9d20fc118446ddccf08e11 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 3 May 2013 16:14:38 +0200 Subject: [PATCH 18/69] osx: show testnet icon in dock as early as possible A green testnet splashscreen with a normal, orange dock icon looks strange and can confuse users. Signed-off-by: Jonas Schnelli --- src/qt/bitcoin.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 25448ea8c..1083f9bfe 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -23,6 +23,10 @@ #include #include +#ifdef Q_OS_MAC +#include "macdockiconhandler.h" +#endif + #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) #define _BITCOIN_QT_PLUGINS_INCLUDED #define __INSURE__ @@ -198,6 +202,13 @@ int main(int argc, char *argv[]) return 1; } +#ifdef Q_OS_MAC + // on mac, also change the icon now because it would look strange to have a testnet splash (green) and a std app icon (orange) + if(GetBoolArg("-testnet")) { + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); + } +#endif + SplashScreen splash(QPixmap(), 0); if (GetBoolArg("-splash", true) && !GetBoolArg("-min")) { From b8e1dc2e53b9d19df26a87686dfd435b3b346f9c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Fri, 3 May 2013 10:45:00 -0400 Subject: [PATCH 19/69] Remove flaky util thread unit tests --- src/test/util_tests.cpp | 58 ----------------------------------------- 1 file changed, 58 deletions(-) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 2d05794cc..1b0ccad51 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -323,62 +323,4 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) } } -static int nCounter = 0; - -static void Count() -{ - ++nCounter; - MilliSleep(10); -} - -static void CountWithArg(int arg) -{ - nCounter += arg; - MilliSleep(10); -} - -BOOST_AUTO_TEST_CASE(util_loop_forever1) -{ - boost::thread_group threadGroup; - - threadGroup.create_thread(boost::bind(&LoopForever, "count", &Count, 1)); - MilliSleep(1); - threadGroup.interrupt_all(); - BOOST_CHECK_EQUAL(nCounter, 1); - nCounter = 0; -} - -BOOST_AUTO_TEST_CASE(util_loop_forever2) -{ - boost::thread_group threadGroup; - - boost::function f = boost::bind(&CountWithArg, 11); - threadGroup.create_thread(boost::bind(&LoopForever >, "count11", f, 11)); - MilliSleep(1); - threadGroup.interrupt_all(); - BOOST_CHECK_EQUAL(nCounter, 11); - nCounter = 0; -} - -BOOST_AUTO_TEST_CASE(util_threadtrace1) -{ - boost::thread_group threadGroup; - - threadGroup.create_thread(boost::bind(&TraceThread, "count11", &Count)); - threadGroup.join_all(); - BOOST_CHECK_EQUAL(nCounter, 1); - nCounter = 0; -} - -BOOST_AUTO_TEST_CASE(util_threadtrace2) -{ - boost::thread_group threadGroup; - - boost::function f = boost::bind(&CountWithArg, 11); - threadGroup.create_thread(boost::bind(&TraceThread >, "count11", f)); - threadGroup.join_all(); - BOOST_CHECK_EQUAL(nCounter, 11); - nCounter = 0; -} - BOOST_AUTO_TEST_SUITE_END() From 8de9bb53af32f7f6b09c06f831f2c0a7b4e95303 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Wed, 24 Apr 2013 18:27:00 -0400 Subject: [PATCH 20/69] Define dust transaction outputs, and make them non-standard --- src/main.cpp | 2 +- src/main.h | 18 ++++++++++++++++++ src/test/script_P2SH_tests.cpp | 5 ++++- src/test/transaction_tests.cpp | 34 ++++++++++++++++++++++------------ src/test/wallet_tests.cpp | 17 ++++++++--------- src/wallet.cpp | 25 +++++++++++++++++++++---- 6 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index aace382d8..d0d6a99eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -384,7 +384,7 @@ bool CTransaction::IsStandard() const BOOST_FOREACH(const CTxOut& txout, vout) { if (!::IsStandard(txout.scriptPubKey)) return false; - if (txout.nValue == 0) + if (txout.IsDust()) return false; } return true; diff --git a/src/main.h b/src/main.h index 24b2cb2aa..8c1e6d265 100644 --- a/src/main.h +++ b/src/main.h @@ -439,6 +439,24 @@ public: return !(a == b); } + size_t size() const + { + return sizeof(nValue)+scriptPubKey.size(); + } + + bool IsDust() const + { + // "Dust" is defined in terms of MIN_RELAY_TX_FEE, which + // has units satoshis-per-kilobyte. + // If you'd pay more than 1/3 in fees + // to spend something, then we consider it dust. + // A typical txout is 32 bytes big, and will + // need a CTxIn of at least 148 bytes to spend, + // so dust is a txout less than 54 uBTC + // (5400 satoshis) + return ((nValue*1000)/(3*(size()+148)) < MIN_RELAY_TX_FEE); + } + std::string ToString() const { if (scriptPubKey.size() < 6) diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 3444726ca..ee0d25a2f 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -78,7 +78,9 @@ BOOST_AUTO_TEST_CASE(sign) for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = evalScripts[i]; + txFrom.vout[i].nValue = COIN; txFrom.vout[i+4].scriptPubKey = standardScripts[i]; + txFrom.vout[i+4].nValue = COIN; } BOOST_CHECK(txFrom.IsStandard()); @@ -169,6 +171,7 @@ BOOST_AUTO_TEST_CASE(set) for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = outer[i]; + txFrom.vout[i].nValue = CENT; } BOOST_CHECK(txFrom.IsStandard()); @@ -179,7 +182,7 @@ BOOST_AUTO_TEST_CASE(set) txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); - txTo[i].vout[0].nValue = 1; + txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].scriptPubKey = inner[i]; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index f44d46fdb..ddff2acd4 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -242,24 +242,34 @@ BOOST_AUTO_TEST_CASE(test_Get) BOOST_CHECK(!t1.AreInputsStandard(coins)); } -BOOST_AUTO_TEST_CASE(test_GetThrow) +BOOST_AUTO_TEST_CASE(test_IsStandard) { CBasicKeyStore keystore; CCoinsView coinsDummy; CCoinsViewCache coins(coinsDummy); std::vector dummyTransactions = SetupDummyInputs(keystore, coins); - CTransaction t1; - t1.vin.resize(3); - t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); - t1.vin[0].prevout.n = 0; - t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();; - t1.vin[1].prevout.n = 0; - t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();; - t1.vin[2].prevout.n = 1; - t1.vout.resize(2); - t1.vout[0].nValue = 90*CENT; - t1.vout[0].scriptPubKey << OP_1; + CTransaction t; + t.vin.resize(1); + t.vin[0].prevout.hash = dummyTransactions[0].GetHash(); + t.vin[0].prevout.n = 1; + t.vin[0].scriptSig << std::vector(65, 0); + t.vout.resize(1); + t.vout[0].nValue = 90*CENT; + CKey key; + key.MakeNewKey(true); + t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + + BOOST_CHECK(t.IsStandard()); + + t.vout[0].nValue = 5011; // dust + BOOST_CHECK(!t.IsStandard()); + + t.vout[0].nValue = 6011; // not dust + BOOST_CHECK(t.IsStandard()); + + t.vout[0].scriptPubKey = CScript() << OP_1; + BOOST_CHECK(!t.IsStandard()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index a4cbfaee4..a14f6b2b7 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -21,13 +21,12 @@ static vector vCoins; static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { - static int i; - CTransaction* tx = new CTransaction; - tx->nLockTime = i++; // so all transactions get different hashes - tx->vout.resize(nInput+1); - tx->vout[nInput].nValue = nValue; - CWalletTx* wtx = new CWalletTx(&wallet, *tx); - delete tx; + static int nextLockTime = 0; + CTransaction tx; + tx.nLockTime = nextLockTime++; // so all transactions get different hashes + tx.vout.resize(nInput+1); + tx.vout[nInput].nValue = nValue; + CWalletTx* wtx = new CWalletTx(&wallet, tx); if (fIsFromMe) { // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(), @@ -55,8 +54,8 @@ static bool equal_sets(CoinSet a, CoinSet b) BOOST_AUTO_TEST_CASE(coin_selection_tests) { - static CoinSet setCoinsRet, setCoinsRet2; - static int64 nValueRet; + CoinSet setCoinsRet, setCoinsRet2; + int64 nValueRet; // test multiple times to allow for differences in the shuffle order for (int i = 0; i < RUN_TESTS; i++) diff --git a/src/wallet.cpp b/src/wallet.cpp index c7eb4f74e..1554b1576 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1162,7 +1162,12 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW double dPriority = 0; // vouts to the payees BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) - wtxNew.vout.push_back(CTxOut(s.second, s.first)); + { + CTxOut txout(s.second, s.first); + if (txout.IsDust()) + return false; + wtxNew.vout.push_back(txout); + } // Choose coins to use set > setCoins; @@ -1208,9 +1213,21 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW CScript scriptChange; scriptChange.SetDestination(vchPubKey.GetID()); - // Insert change txn at random position: - vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); - wtxNew.vout.insert(position, CTxOut(nChange, scriptChange)); + CTxOut newTxOut(nChange, scriptChange); + + // Never create dust outputs; if we would, just + // add the dust to the fee. + if (newTxOut.IsDust()) + { + nFeeRet += nChange; + reservekey.ReturnKey(); + } + else + { + // Insert change txn at random position: + vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); + wtxNew.vout.insert(position, newTxOut); + } } else reservekey.ReturnKey(); From 1f00f4e9c9b4b643da22bb5d9f94d66683fa1a15 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 25 Apr 2013 17:31:22 -0400 Subject: [PATCH 21/69] CreateTransaction: return strFailReason on failure --- src/qt/walletmodel.cpp | 5 ++++- src/rpcwallet.cpp | 9 +++------ src/wallet.cpp | 34 ++++++++++++++++++++++++++-------- src/wallet.h | 6 ++++-- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 20535a451..fb3ffc5c9 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -181,7 +181,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListCreateTransaction(vecSend, wtx, keyChange, nFeeRequired); + std::string strFailReason; + bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); if(!fCreated) { @@ -189,6 +190,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListCreateTransaction(vecSend, wtx, keyChange, nFeeRequired); + string strFailReason; + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); if (!fCreated) - { - if (totalAmount + nFeeRequired > pwalletMain->GetBalance()) - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); - throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed"); - } + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); if (!pwalletMain->CommitTransaction(wtx, keyChange)) throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); diff --git a/src/wallet.cpp b/src/wallet.cpp index 1554b1576..65d2c3b68 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1134,17 +1134,24 @@ bool CWallet::SelectCoins(int64 nTargetValue, set >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(const vector >& vecSend, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason) { int64 nValue = 0; BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) { if (nValue < 0) + { + strFailReason = _("Transaction amounts must be positive"); return false; + } nValue += s.second; } if (vecSend.empty() || nValue < 0) + { + strFailReason = _("Transaction amounts must be positive"); return false; + } wtxNew.BindWallet(this); @@ -1165,7 +1172,10 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW { CTxOut txout(s.second, s.first); if (txout.IsDust()) + { + strFailReason = _("Transaction amount too small"); return false; + } wtxNew.vout.push_back(txout); } @@ -1173,7 +1183,10 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW set > setCoins; int64 nValueIn = 0; if (!SelectCoins(nTotalValue, setCoins, nValueIn)) + { + strFailReason = _("Insufficient funds"); return false; + } BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { int64 nCredit = pcoin.first->vout[pcoin.second].nValue; @@ -1240,12 +1253,18 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW int nIn = 0; BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) + { + strFailReason = _("Signing transaction failed"); return false; + } // Limit size unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); if (nBytes >= MAX_STANDARD_TX_SIZE) + { + strFailReason = _("Transaction too large"); return false; + } dPriority /= nBytes; // Check that enough fee is included @@ -1269,11 +1288,12 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW return true; } -bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason) { vector< pair > vecSend; vecSend.push_back(make_pair(scriptPubKey, nValue)); - return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet); + return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason); } // Call after CreateTransaction unless you want to abort @@ -1339,14 +1359,12 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, printf("SendMoney() : %s", strError.c_str()); return strError; } - if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) + string strError; + if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError)) { - string strError; if (nValue + nFeeRequired > GetBalance()) strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!"), FormatMoney(nFeeRequired).c_str()); - else - strError = _("Error: Transaction creation failed!"); - printf("SendMoney() : %s", strError.c_str()); + printf("SendMoney() : %s\n", strError.c_str()); return strError; } diff --git a/src/wallet.h b/src/wallet.h index 2e007557b..d4ce02105 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -178,8 +178,10 @@ public: int64 GetBalance() const; int64 GetUnconfirmedBalance() const; int64 GetImmatureBalance() const; - bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); - bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); + bool CreateTransaction(const std::vector >& vecSend, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason); + bool CreateTransaction(CScript scriptPubKey, int64 nValue, + CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); std::string SendMoneyToDestination(const CTxDestination &address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); From 000dc55181f77cd96076c76b2cc13f8bcbe4146e Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 25 Apr 2013 20:11:27 -0400 Subject: [PATCH 22/69] Un-hardcode TX_FEE constants Allow setting of MIN_TX_FEE / MIN_RELAY_TX_FEE with -mintxfee / -mintxrelayfee Default values are the same (0.0001 BTC). --- src/init.cpp | 22 ++++++++++++++++++++++ src/main.cpp | 39 ++++++++++++++++++++++++--------------- src/main.h | 24 +++--------------------- src/qt/bitcoin.cpp | 2 +- src/wallet.cpp | 6 +++--- 5 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3845cfad8..058b6a06e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -583,6 +583,28 @@ bool AppInit2(boost::thread_group& threadGroup) const char* pszP2SH = "/P2SH/"; COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); + // Fee-per-kilobyte amount considered the same as "free" + // If you are mining, be careful setting this: + // if you set it to zero then + // a transaction spammer can cheaply fill blocks using + // 1-satoshi-fee transactions. It should be set above the real + // cost to you of processing a transaction. + if (mapArgs.count("-mintxfee")) + { + int64 n = 0; + if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) + CTransaction::nMinTxFee = n; + else + return InitError(strprintf(_("Invalid amount for -mintxfee=: '%s'"), mapArgs["-mintxfee"].c_str())); + } + if (mapArgs.count("-minrelaytxfee")) + { + int64 n = 0; + if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) + CTransaction::nMinRelayTxFee = n; + else + return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%s'"), mapArgs["-minrelaytxfee"].c_str())); + } if (mapArgs.count("-paytxfee")) { diff --git a/src/main.cpp b/src/main.cpp index d0d6a99eb..91e84aefc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,11 @@ bool fBenchmark = false; bool fTxIndex = false; unsigned int nCoinCacheSize = 5000; +/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ +int64 CTransaction::nMinTxFee = 10000; // Override with -mintxfee +/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ +int64 CTransaction::nMinRelayTxFee = 10000; + CMedianFilter cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have map mapOrphanBlocks; @@ -352,9 +357,22 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) ////////////////////////////////////////////////////////////////////////////// // -// CTransaction +// CTransaction / CTxOut // +bool CTxOut::IsDust() const +{ + // "Dust" is defined in terms of CTransaction::nMinRelayTxFee, + // which has units satoshis-per-kilobyte. + // If you'd pay more than 1/3 in fees + // to spend something, then we consider it dust. + // A typical txout is 33 bytes big, and will + // need a CTxIn of at least 148 bytes to spend, + // so dust is a txout less than 54 uBTC + // (5430 satoshis) with default nMinRelayTxFee + return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < CTransaction::nMinRelayTxFee); +} + bool CTransaction::IsStandard() const { if (nVersion > CTransaction::CURRENT_VERSION) @@ -574,8 +592,8 @@ bool CTransaction::CheckTransaction(CValidationState &state) const int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, enum GetMinFee_mode mode) const { - // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE - int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE; + // Base fee is either nMinTxFee or nMinRelayTxFee + int64 nBaseFee = (mode == GMF_RELAY) ? nMinRelayTxFee : nMinTxFee; unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); unsigned int nNewBlockSize = nBlockSize + nBytes; @@ -598,7 +616,7 @@ int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, } } - // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01 + // To limit dust spam, require base fee if any output is less than 0.01 if (nMinFee < nBaseFee) { BOOST_FOREACH(const CTxOut& txout, vout) @@ -746,7 +764,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn // Continuously rate-limit free transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < MIN_RELAY_TX_FEE) + if (fLimitFree && nFees < CTransaction::nMinRelayTxFee) { static double dFreeCount; static int64 nLastTime; @@ -4184,15 +4202,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) unsigned int nBlockMinSize = GetArg("-blockminsize", 0); nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); - // Fee-per-kilobyte amount considered the same as "free" - // Be careful setting this: if you set it to zero then - // a transaction spammer can cheaply fill blocks using - // 1-satoshi-fee transactions. It should be set above the real - // cost to you of processing a transaction. - int64 nMinTxFee = MIN_TX_FEE; - if (mapArgs.count("-mintxfee")) - ParseMoney(mapArgs["-mintxfee"], nMinTxFee); - // Collect memory pool transactions into the block int64 nFees = 0; { @@ -4310,7 +4319,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) continue; // Skip free transactions if we're past the minimum block size: - if (fSortedByFee && (dFeePerKb < nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritize by fee once past the priority size or we run out of high-priority diff --git a/src/main.h b/src/main.h index 8c1e6d265..905b9fbac 100644 --- a/src/main.h +++ b/src/main.h @@ -44,10 +44,6 @@ static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; -/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ -static const int64 MIN_TX_FEE = 10000; -/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ -static const int64 MIN_RELAY_TX_FEE = 10000; /** No amount larger than this (in satoshi) is valid */ static const int64 MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } @@ -439,23 +435,7 @@ public: return !(a == b); } - size_t size() const - { - return sizeof(nValue)+scriptPubKey.size(); - } - - bool IsDust() const - { - // "Dust" is defined in terms of MIN_RELAY_TX_FEE, which - // has units satoshis-per-kilobyte. - // If you'd pay more than 1/3 in fees - // to spend something, then we consider it dust. - // A typical txout is 32 bytes big, and will - // need a CTxIn of at least 148 bytes to spend, - // so dust is a txout less than 54 uBTC - // (5400 satoshis) - return ((nValue*1000)/(3*(size()+148)) < MIN_RELAY_TX_FEE); - } + bool IsDust() const; std::string ToString() const { @@ -485,6 +465,8 @@ enum GetMinFee_mode class CTransaction { public: + static int64 nMinTxFee; + static int64 nMinRelayTxFee; static const int CURRENT_VERSION=1; int nVersion; std::vector vin; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 25448ea8c..5bd808a89 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -69,7 +69,7 @@ static bool ThreadSafeAskFee(int64 nFeeRequired) { if(!guiref) return false; - if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) + if(nFeeRequired < CTransaction::nMinTxFee || nFeeRequired <= nTransactionFee || fDaemon) return true; bool payFee = false; diff --git a/src/wallet.cpp b/src/wallet.cpp index 65d2c3b68..532a73201 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1197,12 +1197,12 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE + // if sub-cent change is required, the fee must be raised to at least nMinTxFee // or until nChange becomes zero // NOTE: this depends on the exact behaviour of GetMinFee - if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT) + if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) { - int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet); + int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); nChange -= nMoveToFee; nFeeRet += nMoveToFee; } From 110257a631455ac7b5c15c027d00bc41c04a2478 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Tue, 30 Apr 2013 18:16:07 +0200 Subject: [PATCH 23/69] small init.cpp changes (strings / Winsock init) - add a check that requested Winsock version is available - update some strings - remove -gen=0 from help-message as this is default --- src/init.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3845cfad8..d82afd712 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -290,8 +290,7 @@ std::string HelpMessage() " -? " + _("This help message") + "\n" + " -conf= " + _("Specify configuration file (default: bitcoin.conf)") + "\n" + " -pid= " + _("Specify pid file (default: bitcoind.pid)") + "\n" + - " -gen " + _("Generate coins") + "\n" + - " -gen=0 " + _("Don't generate coins") + "\n" + + " -gen " + _("Generate coins (default: 0)") + "\n" + " -datadir= " + _("Specify data directory") + "\n" + " -dbcache= " + _("Set database cache size in megabytes (default: 25)") + "\n" + " -timeout= " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n" + @@ -358,7 +357,7 @@ std::string HelpMessage() " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n" + " -loadblock= " + _("Imports blocks from external blk000??.dat file") + "\n" + " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + "\n" + - " -par=N " + _("Set the number of script verification threads (up to 16, 0=auto, negative=leave N CPUs free, default: 0)") + "\n" + + " -par= " + _("Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)") + "\n" + "\n" + _("Block creation options:") + "\n" + " -blockminsize= " + _("Set minimum block size in bytes (default: 0)") + "\n" + @@ -466,9 +465,9 @@ bool AppInit2(boost::thread_group& threadGroup) // Initialize Windows Sockets WSADATA wsadata; int ret = WSAStartup(MAKEWORD(2,2), &wsadata); - if (ret != NO_ERROR) + if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2) { - return InitError(strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret)); + return InitError(strprintf("Error: Winsock library failed to start (WSAStartup returned error %d)", ret)); } #endif #ifndef WIN32 @@ -612,7 +611,7 @@ bool AppInit2(boost::thread_group& threadGroup) if (!fLogTimestamps) printf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); - printf("Used data directory %s\n", strDataDir.c_str()); + printf("Using data directory %s\n", strDataDir.c_str()); printf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); std::ostringstream strErrors; From 64753f0438f66c51ba7ae2173120ae97f22d186e Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 3 May 2013 19:06:34 -0700 Subject: [PATCH 24/69] Remove leveldb in preparation for git-subtree --- src/leveldb/.gitignore | 12 - src/leveldb/AUTHORS | 8 - src/leveldb/LICENSE | 27 - src/leveldb/Makefile | 202 -- src/leveldb/NEWS | 17 - src/leveldb/README | 51 - src/leveldb/TODO | 14 - src/leveldb/WINDOWS.md | 39 - src/leveldb/build_detect_platform | 200 -- src/leveldb/db/builder.cc | 88 - src/leveldb/db/builder.h | 34 - src/leveldb/db/c.cc | 595 ------ src/leveldb/db/c_test.c | 390 ---- src/leveldb/db/corruption_test.cc | 359 ---- src/leveldb/db/db_bench.cc | 979 --------- src/leveldb/db/db_impl.cc | 1467 -------------- src/leveldb/db/db_impl.h | 202 -- src/leveldb/db/db_iter.cc | 299 --- src/leveldb/db/db_iter.h | 26 - src/leveldb/db/db_test.cc | 2027 ------------------- src/leveldb/db/dbformat.cc | 140 -- src/leveldb/db/dbformat.h | 227 --- src/leveldb/db/dbformat_test.cc | 112 - src/leveldb/db/filename.cc | 139 -- src/leveldb/db/filename.h | 80 - src/leveldb/db/filename_test.cc | 122 -- src/leveldb/db/leveldb_main.cc | 238 --- src/leveldb/db/log_format.h | 35 - src/leveldb/db/log_reader.cc | 259 --- src/leveldb/db/log_reader.h | 108 - src/leveldb/db/log_test.cc | 500 ----- src/leveldb/db/log_writer.cc | 103 - src/leveldb/db/log_writer.h | 48 - src/leveldb/db/memtable.cc | 145 -- src/leveldb/db/memtable.h | 91 - src/leveldb/db/repair.cc | 389 ---- src/leveldb/db/skiplist.h | 379 ---- src/leveldb/db/skiplist_test.cc | 378 ---- src/leveldb/db/snapshot.h | 66 - src/leveldb/db/table_cache.cc | 121 -- src/leveldb/db/table_cache.h | 61 - src/leveldb/db/version_edit.cc | 266 --- src/leveldb/db/version_edit.h | 107 - src/leveldb/db/version_edit_test.cc | 46 - src/leveldb/db/version_set.cc | 1438 ------------- src/leveldb/db/version_set.h | 383 ---- src/leveldb/db/version_set_test.cc | 179 -- src/leveldb/db/write_batch.cc | 147 -- src/leveldb/db/write_batch_internal.h | 49 - src/leveldb/db/write_batch_test.cc | 120 -- src/leveldb/doc/bench/db_bench_sqlite3.cc | 718 ------- src/leveldb/doc/bench/db_bench_tree_db.cc | 528 ----- src/leveldb/doc/benchmark.html | 459 ----- src/leveldb/doc/doc.css | 89 - src/leveldb/doc/impl.html | 213 -- src/leveldb/doc/index.html | 549 ----- src/leveldb/doc/log_format.txt | 75 - src/leveldb/doc/table_format.txt | 104 - src/leveldb/helpers/memenv/memenv.cc | 384 ---- src/leveldb/helpers/memenv/memenv.h | 20 - src/leveldb/helpers/memenv/memenv_test.cc | 232 --- src/leveldb/include/leveldb/c.h | 291 --- src/leveldb/include/leveldb/cache.h | 99 - src/leveldb/include/leveldb/comparator.h | 63 - src/leveldb/include/leveldb/db.h | 161 -- src/leveldb/include/leveldb/env.h | 333 --- src/leveldb/include/leveldb/filter_policy.h | 70 - src/leveldb/include/leveldb/iterator.h | 100 - src/leveldb/include/leveldb/options.h | 195 -- src/leveldb/include/leveldb/slice.h | 109 - src/leveldb/include/leveldb/status.h | 106 - src/leveldb/include/leveldb/table.h | 85 - src/leveldb/include/leveldb/table_builder.h | 92 - src/leveldb/include/leveldb/write_batch.h | 64 - src/leveldb/port/README | 10 - src/leveldb/port/atomic_pointer.h | 224 -- src/leveldb/port/port.h | 21 - src/leveldb/port/port_example.h | 135 -- src/leveldb/port/port_posix.cc | 54 - src/leveldb/port/port_posix.h | 157 -- src/leveldb/port/port_win.cc | 149 -- src/leveldb/port/port_win.h | 174 -- src/leveldb/port/thread_annotations.h | 59 - src/leveldb/port/win/stdint.h | 24 - src/leveldb/table/block.cc | 267 --- src/leveldb/table/block.h | 44 - src/leveldb/table/block_builder.cc | 109 - src/leveldb/table/block_builder.h | 57 - src/leveldb/table/filter_block.cc | 111 - src/leveldb/table/filter_block.h | 68 - src/leveldb/table/filter_block_test.cc | 128 -- src/leveldb/table/format.cc | 145 -- src/leveldb/table/format.h | 108 - src/leveldb/table/iterator.cc | 67 - src/leveldb/table/iterator_wrapper.h | 63 - src/leveldb/table/merger.cc | 197 -- src/leveldb/table/merger.h | 26 - src/leveldb/table/table.cc | 276 --- src/leveldb/table/table_builder.cc | 270 --- src/leveldb/table/table_test.cc | 838 -------- src/leveldb/table/two_level_iterator.cc | 182 -- src/leveldb/table/two_level_iterator.h | 34 - src/leveldb/util/arena.cc | 68 - src/leveldb/util/arena.h | 68 - src/leveldb/util/arena_test.cc | 68 - src/leveldb/util/bloom.cc | 95 - src/leveldb/util/bloom_test.cc | 160 -- src/leveldb/util/cache.cc | 328 --- src/leveldb/util/cache_test.cc | 186 -- src/leveldb/util/coding.cc | 194 -- src/leveldb/util/coding.h | 104 - src/leveldb/util/coding_test.cc | 196 -- src/leveldb/util/comparator.cc | 81 - src/leveldb/util/crc32c.cc | 332 --- src/leveldb/util/crc32c.h | 45 - src/leveldb/util/crc32c_test.cc | 72 - src/leveldb/util/env.cc | 96 - src/leveldb/util/env_posix.cc | 701 ------- src/leveldb/util/env_test.cc | 104 - src/leveldb/util/env_win.cc | 1031 ---------- src/leveldb/util/filter_policy.cc | 11 - src/leveldb/util/hash.cc | 45 - src/leveldb/util/hash.h | 19 - src/leveldb/util/histogram.cc | 139 -- src/leveldb/util/histogram.h | 42 - src/leveldb/util/logging.cc | 81 - src/leveldb/util/logging.h | 47 - src/leveldb/util/mutexlock.h | 41 - src/leveldb/util/options.cc | 29 - src/leveldb/util/posix_logger.h | 98 - src/leveldb/util/random.h | 59 - src/leveldb/util/status.cc | 75 - src/leveldb/util/testharness.cc | 77 - src/leveldb/util/testharness.h | 138 -- src/leveldb/util/testutil.cc | 51 - src/leveldb/util/testutil.h | 53 - 136 files changed, 27582 deletions(-) delete mode 100644 src/leveldb/.gitignore delete mode 100644 src/leveldb/AUTHORS delete mode 100644 src/leveldb/LICENSE delete mode 100644 src/leveldb/Makefile delete mode 100644 src/leveldb/NEWS delete mode 100644 src/leveldb/README delete mode 100644 src/leveldb/TODO delete mode 100644 src/leveldb/WINDOWS.md delete mode 100755 src/leveldb/build_detect_platform delete mode 100644 src/leveldb/db/builder.cc delete mode 100644 src/leveldb/db/builder.h delete mode 100644 src/leveldb/db/c.cc delete mode 100644 src/leveldb/db/c_test.c delete mode 100644 src/leveldb/db/corruption_test.cc delete mode 100644 src/leveldb/db/db_bench.cc delete mode 100644 src/leveldb/db/db_impl.cc delete mode 100644 src/leveldb/db/db_impl.h delete mode 100644 src/leveldb/db/db_iter.cc delete mode 100644 src/leveldb/db/db_iter.h delete mode 100644 src/leveldb/db/db_test.cc delete mode 100644 src/leveldb/db/dbformat.cc delete mode 100644 src/leveldb/db/dbformat.h delete mode 100644 src/leveldb/db/dbformat_test.cc delete mode 100644 src/leveldb/db/filename.cc delete mode 100644 src/leveldb/db/filename.h delete mode 100644 src/leveldb/db/filename_test.cc delete mode 100644 src/leveldb/db/leveldb_main.cc delete mode 100644 src/leveldb/db/log_format.h delete mode 100644 src/leveldb/db/log_reader.cc delete mode 100644 src/leveldb/db/log_reader.h delete mode 100644 src/leveldb/db/log_test.cc delete mode 100644 src/leveldb/db/log_writer.cc delete mode 100644 src/leveldb/db/log_writer.h delete mode 100644 src/leveldb/db/memtable.cc delete mode 100644 src/leveldb/db/memtable.h delete mode 100644 src/leveldb/db/repair.cc delete mode 100644 src/leveldb/db/skiplist.h delete mode 100644 src/leveldb/db/skiplist_test.cc delete mode 100644 src/leveldb/db/snapshot.h delete mode 100644 src/leveldb/db/table_cache.cc delete mode 100644 src/leveldb/db/table_cache.h delete mode 100644 src/leveldb/db/version_edit.cc delete mode 100644 src/leveldb/db/version_edit.h delete mode 100644 src/leveldb/db/version_edit_test.cc delete mode 100644 src/leveldb/db/version_set.cc delete mode 100644 src/leveldb/db/version_set.h delete mode 100644 src/leveldb/db/version_set_test.cc delete mode 100644 src/leveldb/db/write_batch.cc delete mode 100644 src/leveldb/db/write_batch_internal.h delete mode 100644 src/leveldb/db/write_batch_test.cc delete mode 100644 src/leveldb/doc/bench/db_bench_sqlite3.cc delete mode 100644 src/leveldb/doc/bench/db_bench_tree_db.cc delete mode 100644 src/leveldb/doc/benchmark.html delete mode 100644 src/leveldb/doc/doc.css delete mode 100644 src/leveldb/doc/impl.html delete mode 100644 src/leveldb/doc/index.html delete mode 100644 src/leveldb/doc/log_format.txt delete mode 100644 src/leveldb/doc/table_format.txt delete mode 100644 src/leveldb/helpers/memenv/memenv.cc delete mode 100644 src/leveldb/helpers/memenv/memenv.h delete mode 100644 src/leveldb/helpers/memenv/memenv_test.cc delete mode 100644 src/leveldb/include/leveldb/c.h delete mode 100644 src/leveldb/include/leveldb/cache.h delete mode 100644 src/leveldb/include/leveldb/comparator.h delete mode 100644 src/leveldb/include/leveldb/db.h delete mode 100644 src/leveldb/include/leveldb/env.h delete mode 100644 src/leveldb/include/leveldb/filter_policy.h delete mode 100644 src/leveldb/include/leveldb/iterator.h delete mode 100644 src/leveldb/include/leveldb/options.h delete mode 100644 src/leveldb/include/leveldb/slice.h delete mode 100644 src/leveldb/include/leveldb/status.h delete mode 100644 src/leveldb/include/leveldb/table.h delete mode 100644 src/leveldb/include/leveldb/table_builder.h delete mode 100644 src/leveldb/include/leveldb/write_batch.h delete mode 100644 src/leveldb/port/README delete mode 100644 src/leveldb/port/atomic_pointer.h delete mode 100644 src/leveldb/port/port.h delete mode 100644 src/leveldb/port/port_example.h delete mode 100644 src/leveldb/port/port_posix.cc delete mode 100644 src/leveldb/port/port_posix.h delete mode 100644 src/leveldb/port/port_win.cc delete mode 100644 src/leveldb/port/port_win.h delete mode 100644 src/leveldb/port/thread_annotations.h delete mode 100644 src/leveldb/port/win/stdint.h delete mode 100644 src/leveldb/table/block.cc delete mode 100644 src/leveldb/table/block.h delete mode 100644 src/leveldb/table/block_builder.cc delete mode 100644 src/leveldb/table/block_builder.h delete mode 100644 src/leveldb/table/filter_block.cc delete mode 100644 src/leveldb/table/filter_block.h delete mode 100644 src/leveldb/table/filter_block_test.cc delete mode 100644 src/leveldb/table/format.cc delete mode 100644 src/leveldb/table/format.h delete mode 100644 src/leveldb/table/iterator.cc delete mode 100644 src/leveldb/table/iterator_wrapper.h delete mode 100644 src/leveldb/table/merger.cc delete mode 100644 src/leveldb/table/merger.h delete mode 100644 src/leveldb/table/table.cc delete mode 100644 src/leveldb/table/table_builder.cc delete mode 100644 src/leveldb/table/table_test.cc delete mode 100644 src/leveldb/table/two_level_iterator.cc delete mode 100644 src/leveldb/table/two_level_iterator.h delete mode 100644 src/leveldb/util/arena.cc delete mode 100644 src/leveldb/util/arena.h delete mode 100644 src/leveldb/util/arena_test.cc delete mode 100644 src/leveldb/util/bloom.cc delete mode 100644 src/leveldb/util/bloom_test.cc delete mode 100644 src/leveldb/util/cache.cc delete mode 100644 src/leveldb/util/cache_test.cc delete mode 100644 src/leveldb/util/coding.cc delete mode 100644 src/leveldb/util/coding.h delete mode 100644 src/leveldb/util/coding_test.cc delete mode 100644 src/leveldb/util/comparator.cc delete mode 100644 src/leveldb/util/crc32c.cc delete mode 100644 src/leveldb/util/crc32c.h delete mode 100644 src/leveldb/util/crc32c_test.cc delete mode 100644 src/leveldb/util/env.cc delete mode 100644 src/leveldb/util/env_posix.cc delete mode 100644 src/leveldb/util/env_test.cc delete mode 100644 src/leveldb/util/env_win.cc delete mode 100644 src/leveldb/util/filter_policy.cc delete mode 100644 src/leveldb/util/hash.cc delete mode 100644 src/leveldb/util/hash.h delete mode 100644 src/leveldb/util/histogram.cc delete mode 100644 src/leveldb/util/histogram.h delete mode 100644 src/leveldb/util/logging.cc delete mode 100644 src/leveldb/util/logging.h delete mode 100644 src/leveldb/util/mutexlock.h delete mode 100644 src/leveldb/util/options.cc delete mode 100644 src/leveldb/util/posix_logger.h delete mode 100644 src/leveldb/util/random.h delete mode 100644 src/leveldb/util/status.cc delete mode 100644 src/leveldb/util/testharness.cc delete mode 100644 src/leveldb/util/testharness.h delete mode 100644 src/leveldb/util/testutil.cc delete mode 100644 src/leveldb/util/testutil.h diff --git a/src/leveldb/.gitignore b/src/leveldb/.gitignore deleted file mode 100644 index 55ba072e0..000000000 --- a/src/leveldb/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -build_config.mk -*.a -*.o -*.dylib* -*.so -*.so.* -*_test -db_bench -Release -Debug -Benchmark -vs2010.* diff --git a/src/leveldb/AUTHORS b/src/leveldb/AUTHORS deleted file mode 100644 index 27a9407e5..000000000 --- a/src/leveldb/AUTHORS +++ /dev/null @@ -1,8 +0,0 @@ -# Names should be added to this file like so: -# Name or Organization - -Google Inc. - -# Initial version authors: -Jeffrey Dean -Sanjay Ghemawat diff --git a/src/leveldb/LICENSE b/src/leveldb/LICENSE deleted file mode 100644 index 8e80208cd..000000000 --- a/src/leveldb/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2011 The LevelDB Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile deleted file mode 100644 index 42c4952fe..000000000 --- a/src/leveldb/Makefile +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright (c) 2011 The LevelDB Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. See the AUTHORS file for names of contributors. - -#----------------------------------------------- -# Uncomment exactly one of the lines labelled (A), (B), and (C) below -# to switch between compilation modes. - -OPT ?= -O2 -DNDEBUG # (A) Production use (optimized mode) -# OPT ?= -g2 # (B) Debug mode, w/ full line-level debugging symbols -# OPT ?= -O2 -g2 -DNDEBUG # (C) Profiling mode: opt, but w/debugging symbols -#----------------------------------------------- - -# detect what platform we're building on -$(shell CC=$(CC) CXX=$(CXX) TARGET_OS=$(TARGET_OS) \ - ./build_detect_platform build_config.mk ./) -# this file is generated by the previous line to set build flags and sources -include build_config.mk - -CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) -CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) - -LDFLAGS += $(PLATFORM_LDFLAGS) -LIBS += $(PLATFORM_LIBS) - -LIBOBJECTS = $(SOURCES:.cc=.o) -MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o) - -TESTUTIL = ./util/testutil.o -TESTHARNESS = ./util/testharness.o $(TESTUTIL) - -TESTS = \ - arena_test \ - bloom_test \ - c_test \ - cache_test \ - coding_test \ - corruption_test \ - crc32c_test \ - db_test \ - dbformat_test \ - env_test \ - filename_test \ - filter_block_test \ - log_test \ - memenv_test \ - skiplist_test \ - table_test \ - version_edit_test \ - version_set_test \ - write_batch_test - -PROGRAMS = db_bench leveldbutil $(TESTS) -BENCHMARKS = db_bench_sqlite3 db_bench_tree_db - -LIBRARY = libleveldb.a -MEMENVLIBRARY = libmemenv.a - -default: all - -# Should we build shared libraries? -ifneq ($(PLATFORM_SHARED_EXT),) - -ifneq ($(PLATFORM_SHARED_VERSIONED),true) -SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) -SHARED2 = $(SHARED1) -SHARED3 = $(SHARED1) -SHARED = $(SHARED1) -else -# Update db.h if you change these. -SHARED_MAJOR = 1 -SHARED_MINOR = 9 -SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) -SHARED2 = $(SHARED1).$(SHARED_MAJOR) -SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) -SHARED = $(SHARED1) $(SHARED2) $(SHARED3) -$(SHARED1): $(SHARED3) - ln -fs $(SHARED3) $(SHARED1) -$(SHARED2): $(SHARED3) - ln -fs $(SHARED3) $(SHARED2) -endif - -$(SHARED3): - $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) $(LIBS) - -endif # PLATFORM_SHARED_EXT - -all: $(SHARED) $(LIBRARY) - -check: all $(PROGRAMS) $(TESTS) - for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done - -clean: - -rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) */*.o */*/*.o ios-x86/*/*.o ios-arm/*/*.o build_config.mk - -rm -rf ios-x86/* ios-arm/* - -$(LIBRARY): $(LIBOBJECTS) - rm -f $@ - $(AR) -rs $@ $(LIBOBJECTS) - -db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) - -db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS) - -db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS) - -leveldbutil: db/leveldb_main.o $(LIBOBJECTS) - $(CXX) $(LDFLAGS) db/leveldb_main.o $(LIBOBJECTS) -o $@ $(LIBS) - -arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -$(MEMENVLIBRARY) : $(MEMENVOBJECTS) - rm -f $@ - $(AR) -rs $@ $(MEMENVOBJECTS) - -memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) - $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS) - -ifeq ($(PLATFORM), IOS) -# For iOS, create universal object files to be used on both the simulator and -# a device. -PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms -SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer -DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer -IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString) - -.cc.o: - mkdir -p ios-x86/$(dir $@) - $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ - mkdir -p ios-arm/$(dir $@) - $(DEVICEROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ - lipo ios-x86/$@ ios-arm/$@ -create -output $@ - -.c.o: - mkdir -p ios-x86/$(dir $@) - $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ - mkdir -p ios-arm/$(dir $@) - $(DEVICEROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ - lipo ios-x86/$@ ios-arm/$@ -create -output $@ - -else -.cc.o: - $(CXX) $(CXXFLAGS) -c $< -o $@ - -.c.o: - $(CC) $(CFLAGS) -c $< -o $@ -endif diff --git a/src/leveldb/NEWS b/src/leveldb/NEWS deleted file mode 100644 index 3fd99242d..000000000 --- a/src/leveldb/NEWS +++ /dev/null @@ -1,17 +0,0 @@ -Release 1.2 2011-05-16 ----------------------- - -Fixes for larger databases (tested up to one billion 100-byte entries, -i.e., ~100GB). - -(1) Place hard limit on number of level-0 files. This fixes errors -of the form "too many open files". - -(2) Fixed memtable management. Before the fix, a heavy write burst -could cause unbounded memory usage. - -A fix for a logging bug where the reader would incorrectly complain -about corruption. - -Allow public access to WriteBatch contents so that users can easily -wrap a DB. diff --git a/src/leveldb/README b/src/leveldb/README deleted file mode 100644 index 3618adeee..000000000 --- a/src/leveldb/README +++ /dev/null @@ -1,51 +0,0 @@ -leveldb: A key-value store -Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) - -The code under this directory implements a system for maintaining a -persistent key/value store. - -See doc/index.html for more explanation. -See doc/impl.html for a brief overview of the implementation. - -The public interface is in include/*.h. Callers should not include or -rely on the details of any other header files in this package. Those -internal APIs may be changed without warning. - -Guide to header files: - -include/db.h - Main interface to the DB: Start here - -include/options.h - Control over the behavior of an entire database, and also - control over the behavior of individual reads and writes. - -include/comparator.h - Abstraction for user-specified comparison function. If you want - just bytewise comparison of keys, you can use the default comparator, - but clients can write their own comparator implementations if they - want custom ordering (e.g. to handle different character - encodings, etc.) - -include/iterator.h - Interface for iterating over data. You can get an iterator - from a DB object. - -include/write_batch.h - Interface for atomically applying multiple updates to a database. - -include/slice.h - A simple module for maintaining a pointer and a length into some - other byte array. - -include/status.h - Status is returned from many of the public interfaces and is used - to report success and various kinds of errors. - -include/env.h - Abstraction of the OS environment. A posix implementation of - this interface is in util/env_posix.cc - -include/table.h -include/table_builder.h - Lower-level modules that most clients probably won't use directly diff --git a/src/leveldb/TODO b/src/leveldb/TODO deleted file mode 100644 index e603c0713..000000000 --- a/src/leveldb/TODO +++ /dev/null @@ -1,14 +0,0 @@ -ss -- Stats - -db -- Maybe implement DB::BulkDeleteForRange(start_key, end_key) - that would blow away files whose ranges are entirely contained - within [start_key..end_key]? For Chrome, deletion of obsolete - object stores, etc. can be done in the background anyway, so - probably not that important. -- There have been requests for MultiGet. - -After a range is completely deleted, what gets rid of the -corresponding files if we do no future changes to that range. Make -the conditions for triggering compactions fire in more situations? diff --git a/src/leveldb/WINDOWS.md b/src/leveldb/WINDOWS.md deleted file mode 100644 index 5b76c2448..000000000 --- a/src/leveldb/WINDOWS.md +++ /dev/null @@ -1,39 +0,0 @@ -# Building LevelDB On Windows - -## Prereqs - -Install the [Windows Software Development Kit version 7.1](http://www.microsoft.com/downloads/dlx/en-us/listdetailsview.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b). - -Download and extract the [Snappy source distribution](http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz) - -1. Open the "Windows SDK 7.1 Command Prompt" : - Start Menu -> "Microsoft Windows SDK v7.1" > "Windows SDK 7.1 Command Prompt" -2. Change the directory to the leveldb project - -## Building the Static lib - -* 32 bit Version - - setenv /x86 - msbuild.exe /p:Configuration=Release /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 - -* 64 bit Version - - setenv /x64 - msbuild.exe /p:Configuration=Release /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 - - -## Building and Running the Benchmark app - -* 32 bit Version - - setenv /x86 - msbuild.exe /p:Configuration=Benchmark /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 - Benchmark\leveldb.exe - -* 64 bit Version - - setenv /x64 - msbuild.exe /p:Configuration=Benchmark /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 - x64\Benchmark\leveldb.exe - diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform deleted file mode 100755 index 609cb5122..000000000 --- a/src/leveldb/build_detect_platform +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/sh -# -# Detects OS we're compiling on and outputs a file specified by the first -# argument, which in turn gets read while processing Makefile. -# -# The output will set the following variables: -# CC C Compiler path -# CXX C++ Compiler path -# PLATFORM_LDFLAGS Linker flags -# PLATFORM_LIBS Libraries flags -# PLATFORM_SHARED_EXT Extension for shared libraries -# PLATFORM_SHARED_LDFLAGS Flags for building shared library -# This flag is embedded just before the name -# of the shared library without intervening spaces -# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library -# PLATFORM_CCFLAGS C compiler flags -# PLATFORM_CXXFLAGS C++ compiler flags. Will contain: -# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned -# shared libraries, empty otherwise. -# -# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following: -# -# -DLEVELDB_CSTDATOMIC_PRESENT if is present -# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms -# -DSNAPPY if the Snappy library is present -# - -OUTPUT=$1 -PREFIX=$2 -if test -z "$OUTPUT" || test -z "$PREFIX"; then - echo "usage: $0 " >&2 - exit 1 -fi - -# Delete existing output, if it exists -rm -f $OUTPUT -touch $OUTPUT - -if test -z "$CC"; then - CC=cc -fi - -if test -z "$CXX"; then - CXX=g++ -fi - -# Detect OS -if test -z "$TARGET_OS"; then - TARGET_OS=`uname -s` -fi - -COMMON_FLAGS= -CROSS_COMPILE= -PLATFORM_CCFLAGS= -PLATFORM_CXXFLAGS= -PLATFORM_LDFLAGS= -PLATFORM_LIBS= -PLATFORM_SHARED_EXT="so" -PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," -PLATFORM_SHARED_CFLAGS="-fPIC" -PLATFORM_SHARED_VERSIONED=true - -MEMCMP_FLAG= -if [ "$CXX" = "g++" ]; then - # Use libc's memcmp instead of GCC's memcmp. This results in ~40% - # performance improvement on readrandom under gcc 4.4.3 on Linux/x86. - MEMCMP_FLAG="-fno-builtin-memcmp" -fi - -case "$TARGET_OS" in - Darwin) - PLATFORM=OS_MACOSX - COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" - PLATFORM_SHARED_EXT=dylib - [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` - PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/" - PORT_FILE=port/port_posix.cc - ;; - Linux) - PLATFORM=OS_LINUX - COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX" - PLATFORM_LDFLAGS="-pthread" - PORT_FILE=port/port_posix.cc - ;; - SunOS) - PLATFORM=OS_SOLARIS - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS" - PLATFORM_LIBS="-lpthread -lrt" - PORT_FILE=port/port_posix.cc - ;; - FreeBSD) - PLATFORM=OS_FREEBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD" - PLATFORM_LIBS="-lpthread" - PORT_FILE=port/port_posix.cc - ;; - NetBSD) - PLATFORM=OS_NETBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" - PLATFORM_LIBS="-lpthread -lgcc_s" - PORT_FILE=port/port_posix.cc - ;; - OpenBSD) - PLATFORM=OS_OPENBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD" - PLATFORM_LDFLAGS="-pthread" - PORT_FILE=port/port_posix.cc - ;; - DragonFly) - PLATFORM=OS_DRAGONFLYBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD" - PLATFORM_LIBS="-lpthread" - PORT_FILE=port/port_posix.cc - ;; - OS_ANDROID_CROSSCOMPILE) - PLATFORM=OS_ANDROID - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" - PLATFORM_LDFLAGS="" # All pthread features are in the Android C library - PORT_FILE=port/port_posix.cc - CROSS_COMPILE=true - ;; - HP-UX) - PLATFORM=OS_HPUX - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX" - PLATFORM_LDFLAGS="-pthread" - PORT_FILE=port/port_posix.cc - # man ld: +h internal_name - PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl," - ;; - OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) - PLATFORM=OS_WINDOWS - COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1" - PLATFORM_SOURCES="util/env_win.cc" - PLATFORM_LIBS="-lshlwapi" - PORT_FILE=port/port_win.cc - CROSS_COMPILE=true - ;; - *) - echo "Unknown platform!" >&2 - exit 1 -esac - -# We want to make a list of all cc files within util, db, table, and helpers -# except for the test and benchmark files. By default, find will output a list -# of all files matching either rule, so we need to append -print to make the -# prune take effect. -DIRS="$PREFIX/db $PREFIX/util $PREFIX/table" - -set -f # temporarily disable globbing so that our patterns aren't expanded -PRUNE_TEST="-name *test*.cc -prune" -PRUNE_BENCH="-name *_bench.cc -prune" -PRUNE_TOOL="-name leveldb_main.cc -prune" -PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "` - -set +f # re-enable globbing - -# The sources consist of the portable files, plus the platform-specific port -# file. -echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT -echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT - -if [ "$CROSS_COMPILE" = "true" ]; then - # Cross-compiling; do not try any compilation tests. - true -else - # If -std=c++0x works, use . Otherwise use port_posix.h. - $CXX $CXXFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null < - int main() {} -EOF - if [ "$?" = 0 ]; then - COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_CSTDATOMIC_PRESENT" - PLATFORM_CXXFLAGS="-std=c++0x" - else - COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX" - fi - - # Test whether tcmalloc is available - $CXX $CXXFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null <> $OUTPUT -echo "CXX=$CXX" >> $OUTPUT -echo "PLATFORM=$PLATFORM" >> $OUTPUT -echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT -echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT -echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT -echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT -echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT -echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT -echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT -echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT diff --git a/src/leveldb/db/builder.cc b/src/leveldb/db/builder.cc deleted file mode 100644 index f41988219..000000000 --- a/src/leveldb/db/builder.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/builder.h" - -#include "db/filename.h" -#include "db/dbformat.h" -#include "db/table_cache.h" -#include "db/version_edit.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" - -namespace leveldb { - -Status BuildTable(const std::string& dbname, - Env* env, - const Options& options, - TableCache* table_cache, - Iterator* iter, - FileMetaData* meta) { - Status s; - meta->file_size = 0; - iter->SeekToFirst(); - - std::string fname = TableFileName(dbname, meta->number); - if (iter->Valid()) { - WritableFile* file; - s = env->NewWritableFile(fname, &file); - if (!s.ok()) { - return s; - } - - TableBuilder* builder = new TableBuilder(options, file); - meta->smallest.DecodeFrom(iter->key()); - for (; iter->Valid(); iter->Next()) { - Slice key = iter->key(); - meta->largest.DecodeFrom(key); - builder->Add(key, iter->value()); - } - - // Finish and check for builder errors - if (s.ok()) { - s = builder->Finish(); - if (s.ok()) { - meta->file_size = builder->FileSize(); - assert(meta->file_size > 0); - } - } else { - builder->Abandon(); - } - delete builder; - - // Finish and check for file errors - if (s.ok()) { - s = file->Sync(); - } - if (s.ok()) { - s = file->Close(); - } - delete file; - file = NULL; - - if (s.ok()) { - // Verify that the table is usable - Iterator* it = table_cache->NewIterator(ReadOptions(), - meta->number, - meta->file_size); - s = it->status(); - delete it; - } - } - - // Check for input iterator errors - if (!iter->status().ok()) { - s = iter->status(); - } - - if (s.ok() && meta->file_size > 0) { - // Keep it - } else { - env->DeleteFile(fname); - } - return s; -} - -} // namespace leveldb diff --git a/src/leveldb/db/builder.h b/src/leveldb/db/builder.h deleted file mode 100644 index 62431fcf4..000000000 --- a/src/leveldb/db/builder.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ -#define STORAGE_LEVELDB_DB_BUILDER_H_ - -#include "leveldb/status.h" - -namespace leveldb { - -struct Options; -struct FileMetaData; - -class Env; -class Iterator; -class TableCache; -class VersionEdit; - -// Build a Table file from the contents of *iter. The generated file -// will be named according to meta->number. On success, the rest of -// *meta will be filled with metadata about the generated table. -// If no data is present in *iter, meta->file_size will be set to -// zero, and no Table file will be produced. -extern Status BuildTable(const std::string& dbname, - Env* env, - const Options& options, - TableCache* table_cache, - Iterator* iter, - FileMetaData* meta); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/src/leveldb/db/c.cc b/src/leveldb/db/c.cc deleted file mode 100644 index 08ff0ad90..000000000 --- a/src/leveldb/db/c.cc +++ /dev/null @@ -1,595 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/c.h" - -#include -#include -#include "leveldb/cache.h" -#include "leveldb/comparator.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/filter_policy.h" -#include "leveldb/iterator.h" -#include "leveldb/options.h" -#include "leveldb/status.h" -#include "leveldb/write_batch.h" - -using leveldb::Cache; -using leveldb::Comparator; -using leveldb::CompressionType; -using leveldb::DB; -using leveldb::Env; -using leveldb::FileLock; -using leveldb::FilterPolicy; -using leveldb::Iterator; -using leveldb::kMajorVersion; -using leveldb::kMinorVersion; -using leveldb::Logger; -using leveldb::NewBloomFilterPolicy; -using leveldb::NewLRUCache; -using leveldb::Options; -using leveldb::RandomAccessFile; -using leveldb::Range; -using leveldb::ReadOptions; -using leveldb::SequentialFile; -using leveldb::Slice; -using leveldb::Snapshot; -using leveldb::Status; -using leveldb::WritableFile; -using leveldb::WriteBatch; -using leveldb::WriteOptions; - -extern "C" { - -struct leveldb_t { DB* rep; }; -struct leveldb_iterator_t { Iterator* rep; }; -struct leveldb_writebatch_t { WriteBatch rep; }; -struct leveldb_snapshot_t { const Snapshot* rep; }; -struct leveldb_readoptions_t { ReadOptions rep; }; -struct leveldb_writeoptions_t { WriteOptions rep; }; -struct leveldb_options_t { Options rep; }; -struct leveldb_cache_t { Cache* rep; }; -struct leveldb_seqfile_t { SequentialFile* rep; }; -struct leveldb_randomfile_t { RandomAccessFile* rep; }; -struct leveldb_writablefile_t { WritableFile* rep; }; -struct leveldb_logger_t { Logger* rep; }; -struct leveldb_filelock_t { FileLock* rep; }; - -struct leveldb_comparator_t : public Comparator { - void* state_; - void (*destructor_)(void*); - int (*compare_)( - void*, - const char* a, size_t alen, - const char* b, size_t blen); - const char* (*name_)(void*); - - virtual ~leveldb_comparator_t() { - (*destructor_)(state_); - } - - virtual int Compare(const Slice& a, const Slice& b) const { - return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); - } - - virtual const char* Name() const { - return (*name_)(state_); - } - - // No-ops since the C binding does not support key shortening methods. - virtual void FindShortestSeparator(std::string*, const Slice&) const { } - virtual void FindShortSuccessor(std::string* key) const { } -}; - -struct leveldb_filterpolicy_t : public FilterPolicy { - void* state_; - void (*destructor_)(void*); - const char* (*name_)(void*); - char* (*create_)( - void*, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length); - unsigned char (*key_match_)( - void*, - const char* key, size_t length, - const char* filter, size_t filter_length); - - virtual ~leveldb_filterpolicy_t() { - (*destructor_)(state_); - } - - virtual const char* Name() const { - return (*name_)(state_); - } - - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { - std::vector key_pointers(n); - std::vector key_sizes(n); - for (int i = 0; i < n; i++) { - key_pointers[i] = keys[i].data(); - key_sizes[i] = keys[i].size(); - } - size_t len; - char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); - dst->append(filter, len); - free(filter); - } - - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { - return (*key_match_)(state_, key.data(), key.size(), - filter.data(), filter.size()); - } -}; - -struct leveldb_env_t { - Env* rep; - bool is_default; -}; - -static bool SaveError(char** errptr, const Status& s) { - assert(errptr != NULL); - if (s.ok()) { - return false; - } else if (*errptr == NULL) { - *errptr = strdup(s.ToString().c_str()); - } else { - // TODO(sanjay): Merge with existing error? - free(*errptr); - *errptr = strdup(s.ToString().c_str()); - } - return true; -} - -static char* CopyString(const std::string& str) { - char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); - memcpy(result, str.data(), sizeof(char) * str.size()); - return result; -} - -leveldb_t* leveldb_open( - const leveldb_options_t* options, - const char* name, - char** errptr) { - DB* db; - if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { - return NULL; - } - leveldb_t* result = new leveldb_t; - result->rep = db; - return result; -} - -void leveldb_close(leveldb_t* db) { - delete db->rep; - delete db; -} - -void leveldb_put( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - const char* val, size_t vallen, - char** errptr) { - SaveError(errptr, - db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); -} - -void leveldb_delete( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - char** errptr) { - SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); -} - - -void leveldb_write( - leveldb_t* db, - const leveldb_writeoptions_t* options, - leveldb_writebatch_t* batch, - char** errptr) { - SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); -} - -char* leveldb_get( - leveldb_t* db, - const leveldb_readoptions_t* options, - const char* key, size_t keylen, - size_t* vallen, - char** errptr) { - char* result = NULL; - std::string tmp; - Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); - if (s.ok()) { - *vallen = tmp.size(); - result = CopyString(tmp); - } else { - *vallen = 0; - if (!s.IsNotFound()) { - SaveError(errptr, s); - } - } - return result; -} - -leveldb_iterator_t* leveldb_create_iterator( - leveldb_t* db, - const leveldb_readoptions_t* options) { - leveldb_iterator_t* result = new leveldb_iterator_t; - result->rep = db->rep->NewIterator(options->rep); - return result; -} - -const leveldb_snapshot_t* leveldb_create_snapshot( - leveldb_t* db) { - leveldb_snapshot_t* result = new leveldb_snapshot_t; - result->rep = db->rep->GetSnapshot(); - return result; -} - -void leveldb_release_snapshot( - leveldb_t* db, - const leveldb_snapshot_t* snapshot) { - db->rep->ReleaseSnapshot(snapshot->rep); - delete snapshot; -} - -char* leveldb_property_value( - leveldb_t* db, - const char* propname) { - std::string tmp; - if (db->rep->GetProperty(Slice(propname), &tmp)) { - // We use strdup() since we expect human readable output. - return strdup(tmp.c_str()); - } else { - return NULL; - } -} - -void leveldb_approximate_sizes( - leveldb_t* db, - int num_ranges, - const char* const* range_start_key, const size_t* range_start_key_len, - const char* const* range_limit_key, const size_t* range_limit_key_len, - uint64_t* sizes) { - Range* ranges = new Range[num_ranges]; - for (int i = 0; i < num_ranges; i++) { - ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); - ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); - } - db->rep->GetApproximateSizes(ranges, num_ranges, sizes); - delete[] ranges; -} - -void leveldb_compact_range( - leveldb_t* db, - const char* start_key, size_t start_key_len, - const char* limit_key, size_t limit_key_len) { - Slice a, b; - db->rep->CompactRange( - // Pass NULL Slice if corresponding "const char*" is NULL - (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), - (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); -} - -void leveldb_destroy_db( - const leveldb_options_t* options, - const char* name, - char** errptr) { - SaveError(errptr, DestroyDB(name, options->rep)); -} - -void leveldb_repair_db( - const leveldb_options_t* options, - const char* name, - char** errptr) { - SaveError(errptr, RepairDB(name, options->rep)); -} - -void leveldb_iter_destroy(leveldb_iterator_t* iter) { - delete iter->rep; - delete iter; -} - -unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { - return iter->rep->Valid(); -} - -void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { - iter->rep->SeekToFirst(); -} - -void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { - iter->rep->SeekToLast(); -} - -void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { - iter->rep->Seek(Slice(k, klen)); -} - -void leveldb_iter_next(leveldb_iterator_t* iter) { - iter->rep->Next(); -} - -void leveldb_iter_prev(leveldb_iterator_t* iter) { - iter->rep->Prev(); -} - -const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { - Slice s = iter->rep->key(); - *klen = s.size(); - return s.data(); -} - -const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { - Slice s = iter->rep->value(); - *vlen = s.size(); - return s.data(); -} - -void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { - SaveError(errptr, iter->rep->status()); -} - -leveldb_writebatch_t* leveldb_writebatch_create() { - return new leveldb_writebatch_t; -} - -void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { - delete b; -} - -void leveldb_writebatch_clear(leveldb_writebatch_t* b) { - b->rep.Clear(); -} - -void leveldb_writebatch_put( - leveldb_writebatch_t* b, - const char* key, size_t klen, - const char* val, size_t vlen) { - b->rep.Put(Slice(key, klen), Slice(val, vlen)); -} - -void leveldb_writebatch_delete( - leveldb_writebatch_t* b, - const char* key, size_t klen) { - b->rep.Delete(Slice(key, klen)); -} - -void leveldb_writebatch_iterate( - leveldb_writebatch_t* b, - void* state, - void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), - void (*deleted)(void*, const char* k, size_t klen)) { - class H : public WriteBatch::Handler { - public: - void* state_; - void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); - void (*deleted_)(void*, const char* k, size_t klen); - virtual void Put(const Slice& key, const Slice& value) { - (*put_)(state_, key.data(), key.size(), value.data(), value.size()); - } - virtual void Delete(const Slice& key) { - (*deleted_)(state_, key.data(), key.size()); - } - }; - H handler; - handler.state_ = state; - handler.put_ = put; - handler.deleted_ = deleted; - b->rep.Iterate(&handler); -} - -leveldb_options_t* leveldb_options_create() { - return new leveldb_options_t; -} - -void leveldb_options_destroy(leveldb_options_t* options) { - delete options; -} - -void leveldb_options_set_comparator( - leveldb_options_t* opt, - leveldb_comparator_t* cmp) { - opt->rep.comparator = cmp; -} - -void leveldb_options_set_filter_policy( - leveldb_options_t* opt, - leveldb_filterpolicy_t* policy) { - opt->rep.filter_policy = policy; -} - -void leveldb_options_set_create_if_missing( - leveldb_options_t* opt, unsigned char v) { - opt->rep.create_if_missing = v; -} - -void leveldb_options_set_error_if_exists( - leveldb_options_t* opt, unsigned char v) { - opt->rep.error_if_exists = v; -} - -void leveldb_options_set_paranoid_checks( - leveldb_options_t* opt, unsigned char v) { - opt->rep.paranoid_checks = v; -} - -void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { - opt->rep.env = (env ? env->rep : NULL); -} - -void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { - opt->rep.info_log = (l ? l->rep : NULL); -} - -void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { - opt->rep.write_buffer_size = s; -} - -void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { - opt->rep.max_open_files = n; -} - -void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { - opt->rep.block_cache = c->rep; -} - -void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { - opt->rep.block_size = s; -} - -void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { - opt->rep.block_restart_interval = n; -} - -void leveldb_options_set_compression(leveldb_options_t* opt, int t) { - opt->rep.compression = static_cast(t); -} - -leveldb_comparator_t* leveldb_comparator_create( - void* state, - void (*destructor)(void*), - int (*compare)( - void*, - const char* a, size_t alen, - const char* b, size_t blen), - const char* (*name)(void*)) { - leveldb_comparator_t* result = new leveldb_comparator_t; - result->state_ = state; - result->destructor_ = destructor; - result->compare_ = compare; - result->name_ = name; - return result; -} - -void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { - delete cmp; -} - -leveldb_filterpolicy_t* leveldb_filterpolicy_create( - void* state, - void (*destructor)(void*), - char* (*create_filter)( - void*, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length), - unsigned char (*key_may_match)( - void*, - const char* key, size_t length, - const char* filter, size_t filter_length), - const char* (*name)(void*)) { - leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; - result->state_ = state; - result->destructor_ = destructor; - result->create_ = create_filter; - result->key_match_ = key_may_match; - result->name_ = name; - return result; -} - -void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { - delete filter; -} - -leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { - // Make a leveldb_filterpolicy_t, but override all of its methods so - // they delegate to a NewBloomFilterPolicy() instead of user - // supplied C functions. - struct Wrapper : public leveldb_filterpolicy_t { - const FilterPolicy* rep_; - ~Wrapper() { delete rep_; } - const char* Name() const { return rep_->Name(); } - void CreateFilter(const Slice* keys, int n, std::string* dst) const { - return rep_->CreateFilter(keys, n, dst); - } - bool KeyMayMatch(const Slice& key, const Slice& filter) const { - return rep_->KeyMayMatch(key, filter); - } - static void DoNothing(void*) { } - }; - Wrapper* wrapper = new Wrapper; - wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); - wrapper->state_ = NULL; - wrapper->destructor_ = &Wrapper::DoNothing; - return wrapper; -} - -leveldb_readoptions_t* leveldb_readoptions_create() { - return new leveldb_readoptions_t; -} - -void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { - delete opt; -} - -void leveldb_readoptions_set_verify_checksums( - leveldb_readoptions_t* opt, - unsigned char v) { - opt->rep.verify_checksums = v; -} - -void leveldb_readoptions_set_fill_cache( - leveldb_readoptions_t* opt, unsigned char v) { - opt->rep.fill_cache = v; -} - -void leveldb_readoptions_set_snapshot( - leveldb_readoptions_t* opt, - const leveldb_snapshot_t* snap) { - opt->rep.snapshot = (snap ? snap->rep : NULL); -} - -leveldb_writeoptions_t* leveldb_writeoptions_create() { - return new leveldb_writeoptions_t; -} - -void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { - delete opt; -} - -void leveldb_writeoptions_set_sync( - leveldb_writeoptions_t* opt, unsigned char v) { - opt->rep.sync = v; -} - -leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { - leveldb_cache_t* c = new leveldb_cache_t; - c->rep = NewLRUCache(capacity); - return c; -} - -void leveldb_cache_destroy(leveldb_cache_t* cache) { - delete cache->rep; - delete cache; -} - -leveldb_env_t* leveldb_create_default_env() { - leveldb_env_t* result = new leveldb_env_t; - result->rep = Env::Default(); - result->is_default = true; - return result; -} - -void leveldb_env_destroy(leveldb_env_t* env) { - if (!env->is_default) delete env->rep; - delete env; -} - -void leveldb_free(void* ptr) { - free(ptr); -} - -int leveldb_major_version() { - return kMajorVersion; -} - -int leveldb_minor_version() { - return kMinorVersion; -} - -} // end extern "C" diff --git a/src/leveldb/db/c_test.c b/src/leveldb/db/c_test.c deleted file mode 100644 index 7cd5ee020..000000000 --- a/src/leveldb/db/c_test.c +++ /dev/null @@ -1,390 +0,0 @@ -/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. See the AUTHORS file for names of contributors. */ - -#include "leveldb/c.h" - -#include -#include -#include -#include -#include -#include - -const char* phase = ""; -static char dbname[200]; - -static void StartPhase(const char* name) { - fprintf(stderr, "=== Test %s\n", name); - phase = name; -} - -static const char* GetTempDir(void) { - const char* ret = getenv("TEST_TMPDIR"); - if (ret == NULL || ret[0] == '\0') - ret = "/tmp"; - return ret; -} - -#define CheckNoError(err) \ - if ((err) != NULL) { \ - fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ - abort(); \ - } - -#define CheckCondition(cond) \ - if (!(cond)) { \ - fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ - abort(); \ - } - -static void CheckEqual(const char* expected, const char* v, size_t n) { - if (expected == NULL && v == NULL) { - // ok - } else if (expected != NULL && v != NULL && n == strlen(expected) && - memcmp(expected, v, n) == 0) { - // ok - return; - } else { - fprintf(stderr, "%s: expected '%s', got '%s'\n", - phase, - (expected ? expected : "(null)"), - (v ? v : "(null")); - abort(); - } -} - -static void Free(char** ptr) { - if (*ptr) { - free(*ptr); - *ptr = NULL; - } -} - -static void CheckGet( - leveldb_t* db, - const leveldb_readoptions_t* options, - const char* key, - const char* expected) { - char* err = NULL; - size_t val_len; - char* val; - val = leveldb_get(db, options, key, strlen(key), &val_len, &err); - CheckNoError(err); - CheckEqual(expected, val, val_len); - Free(&val); -} - -static void CheckIter(leveldb_iterator_t* iter, - const char* key, const char* val) { - size_t len; - const char* str; - str = leveldb_iter_key(iter, &len); - CheckEqual(key, str, len); - str = leveldb_iter_value(iter, &len); - CheckEqual(val, str, len); -} - -// Callback from leveldb_writebatch_iterate() -static void CheckPut(void* ptr, - const char* k, size_t klen, - const char* v, size_t vlen) { - int* state = (int*) ptr; - CheckCondition(*state < 2); - switch (*state) { - case 0: - CheckEqual("bar", k, klen); - CheckEqual("b", v, vlen); - break; - case 1: - CheckEqual("box", k, klen); - CheckEqual("c", v, vlen); - break; - } - (*state)++; -} - -// Callback from leveldb_writebatch_iterate() -static void CheckDel(void* ptr, const char* k, size_t klen) { - int* state = (int*) ptr; - CheckCondition(*state == 2); - CheckEqual("bar", k, klen); - (*state)++; -} - -static void CmpDestroy(void* arg) { } - -static int CmpCompare(void* arg, const char* a, size_t alen, - const char* b, size_t blen) { - int n = (alen < blen) ? alen : blen; - int r = memcmp(a, b, n); - if (r == 0) { - if (alen < blen) r = -1; - else if (alen > blen) r = +1; - } - return r; -} - -static const char* CmpName(void* arg) { - return "foo"; -} - -// Custom filter policy -static unsigned char fake_filter_result = 1; -static void FilterDestroy(void* arg) { } -static const char* FilterName(void* arg) { - return "TestFilter"; -} -static char* FilterCreate( - void* arg, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length) { - *filter_length = 4; - char* result = malloc(4); - memcpy(result, "fake", 4); - return result; -} -unsigned char FilterKeyMatch( - void* arg, - const char* key, size_t length, - const char* filter, size_t filter_length) { - CheckCondition(filter_length == 4); - CheckCondition(memcmp(filter, "fake", 4) == 0); - return fake_filter_result; -} - -int main(int argc, char** argv) { - leveldb_t* db; - leveldb_comparator_t* cmp; - leveldb_cache_t* cache; - leveldb_env_t* env; - leveldb_options_t* options; - leveldb_readoptions_t* roptions; - leveldb_writeoptions_t* woptions; - char* err = NULL; - int run = -1; - - CheckCondition(leveldb_major_version() >= 1); - CheckCondition(leveldb_minor_version() >= 1); - - snprintf(dbname, sizeof(dbname), - "%s/leveldb_c_test-%d", - GetTempDir(), - ((int) geteuid())); - - StartPhase("create_objects"); - cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); - env = leveldb_create_default_env(); - cache = leveldb_cache_create_lru(100000); - - options = leveldb_options_create(); - leveldb_options_set_comparator(options, cmp); - leveldb_options_set_error_if_exists(options, 1); - leveldb_options_set_cache(options, cache); - leveldb_options_set_env(options, env); - leveldb_options_set_info_log(options, NULL); - leveldb_options_set_write_buffer_size(options, 100000); - leveldb_options_set_paranoid_checks(options, 1); - leveldb_options_set_max_open_files(options, 10); - leveldb_options_set_block_size(options, 1024); - leveldb_options_set_block_restart_interval(options, 8); - leveldb_options_set_compression(options, leveldb_no_compression); - - roptions = leveldb_readoptions_create(); - leveldb_readoptions_set_verify_checksums(roptions, 1); - leveldb_readoptions_set_fill_cache(roptions, 0); - - woptions = leveldb_writeoptions_create(); - leveldb_writeoptions_set_sync(woptions, 1); - - StartPhase("destroy"); - leveldb_destroy_db(options, dbname, &err); - Free(&err); - - StartPhase("open_error"); - db = leveldb_open(options, dbname, &err); - CheckCondition(err != NULL); - Free(&err); - - StartPhase("leveldb_free"); - db = leveldb_open(options, dbname, &err); - CheckCondition(err != NULL); - leveldb_free(err); - err = NULL; - - StartPhase("open"); - leveldb_options_set_create_if_missing(options, 1); - db = leveldb_open(options, dbname, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", NULL); - - StartPhase("put"); - leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", "hello"); - - StartPhase("compactall"); - leveldb_compact_range(db, NULL, 0, NULL, 0); - CheckGet(db, roptions, "foo", "hello"); - - StartPhase("compactrange"); - leveldb_compact_range(db, "a", 1, "z", 1); - CheckGet(db, roptions, "foo", "hello"); - - StartPhase("writebatch"); - { - leveldb_writebatch_t* wb = leveldb_writebatch_create(); - leveldb_writebatch_put(wb, "foo", 3, "a", 1); - leveldb_writebatch_clear(wb); - leveldb_writebatch_put(wb, "bar", 3, "b", 1); - leveldb_writebatch_put(wb, "box", 3, "c", 1); - leveldb_writebatch_delete(wb, "bar", 3); - leveldb_write(db, woptions, wb, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", "hello"); - CheckGet(db, roptions, "bar", NULL); - CheckGet(db, roptions, "box", "c"); - int pos = 0; - leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); - CheckCondition(pos == 3); - leveldb_writebatch_destroy(wb); - } - - StartPhase("iter"); - { - leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions); - CheckCondition(!leveldb_iter_valid(iter)); - leveldb_iter_seek_to_first(iter); - CheckCondition(leveldb_iter_valid(iter)); - CheckIter(iter, "box", "c"); - leveldb_iter_next(iter); - CheckIter(iter, "foo", "hello"); - leveldb_iter_prev(iter); - CheckIter(iter, "box", "c"); - leveldb_iter_prev(iter); - CheckCondition(!leveldb_iter_valid(iter)); - leveldb_iter_seek_to_last(iter); - CheckIter(iter, "foo", "hello"); - leveldb_iter_seek(iter, "b", 1); - CheckIter(iter, "box", "c"); - leveldb_iter_get_error(iter, &err); - CheckNoError(err); - leveldb_iter_destroy(iter); - } - - StartPhase("approximate_sizes"); - { - int i; - int n = 20000; - char keybuf[100]; - char valbuf[100]; - uint64_t sizes[2]; - const char* start[2] = { "a", "k00000000000000010000" }; - size_t start_len[2] = { 1, 21 }; - const char* limit[2] = { "k00000000000000010000", "z" }; - size_t limit_len[2] = { 21, 1 }; - leveldb_writeoptions_set_sync(woptions, 0); - for (i = 0; i < n; i++) { - snprintf(keybuf, sizeof(keybuf), "k%020d", i); - snprintf(valbuf, sizeof(valbuf), "v%020d", i); - leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf), - &err); - CheckNoError(err); - } - leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes); - CheckCondition(sizes[0] > 0); - CheckCondition(sizes[1] > 0); - } - - StartPhase("property"); - { - char* prop = leveldb_property_value(db, "nosuchprop"); - CheckCondition(prop == NULL); - prop = leveldb_property_value(db, "leveldb.stats"); - CheckCondition(prop != NULL); - Free(&prop); - } - - StartPhase("snapshot"); - { - const leveldb_snapshot_t* snap; - snap = leveldb_create_snapshot(db); - leveldb_delete(db, woptions, "foo", 3, &err); - CheckNoError(err); - leveldb_readoptions_set_snapshot(roptions, snap); - CheckGet(db, roptions, "foo", "hello"); - leveldb_readoptions_set_snapshot(roptions, NULL); - CheckGet(db, roptions, "foo", NULL); - leveldb_release_snapshot(db, snap); - } - - StartPhase("repair"); - { - leveldb_close(db); - leveldb_options_set_create_if_missing(options, 0); - leveldb_options_set_error_if_exists(options, 0); - leveldb_repair_db(options, dbname, &err); - CheckNoError(err); - db = leveldb_open(options, dbname, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", NULL); - CheckGet(db, roptions, "bar", NULL); - CheckGet(db, roptions, "box", "c"); - leveldb_options_set_create_if_missing(options, 1); - leveldb_options_set_error_if_exists(options, 1); - } - - StartPhase("filter"); - for (run = 0; run < 2; run++) { - // First run uses custom filter, second run uses bloom filter - CheckNoError(err); - leveldb_filterpolicy_t* policy; - if (run == 0) { - policy = leveldb_filterpolicy_create( - NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName); - } else { - policy = leveldb_filterpolicy_create_bloom(10); - } - - // Create new database - leveldb_close(db); - leveldb_destroy_db(options, dbname, &err); - leveldb_options_set_filter_policy(options, policy); - db = leveldb_open(options, dbname, &err); - CheckNoError(err); - leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err); - CheckNoError(err); - leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err); - CheckNoError(err); - leveldb_compact_range(db, NULL, 0, NULL, 0); - - fake_filter_result = 1; - CheckGet(db, roptions, "foo", "foovalue"); - CheckGet(db, roptions, "bar", "barvalue"); - if (phase == 0) { - // Must not find value when custom filter returns false - fake_filter_result = 0; - CheckGet(db, roptions, "foo", NULL); - CheckGet(db, roptions, "bar", NULL); - fake_filter_result = 1; - - CheckGet(db, roptions, "foo", "foovalue"); - CheckGet(db, roptions, "bar", "barvalue"); - } - leveldb_options_set_filter_policy(options, NULL); - leveldb_filterpolicy_destroy(policy); - } - - StartPhase("cleanup"); - leveldb_close(db); - leveldb_options_destroy(options); - leveldb_readoptions_destroy(roptions); - leveldb_writeoptions_destroy(woptions); - leveldb_cache_destroy(cache); - leveldb_comparator_destroy(cmp); - leveldb_env_destroy(env); - - fprintf(stderr, "PASS\n"); - return 0; -} diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc deleted file mode 100644 index 31b2d5f41..000000000 --- a/src/leveldb/db/corruption_test.cc +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" - -#include -#include -#include -#include -#include "leveldb/cache.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "leveldb/write_batch.h" -#include "db/db_impl.h" -#include "db/filename.h" -#include "db/log_format.h" -#include "db/version_set.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static const int kValueSize = 1000; - -class CorruptionTest { - public: - test::ErrorEnv env_; - std::string dbname_; - Cache* tiny_cache_; - Options options_; - DB* db_; - - CorruptionTest() { - tiny_cache_ = NewLRUCache(100); - options_.env = &env_; - dbname_ = test::TmpDir() + "/db_test"; - DestroyDB(dbname_, options_); - - db_ = NULL; - options_.create_if_missing = true; - Reopen(); - options_.create_if_missing = false; - } - - ~CorruptionTest() { - delete db_; - DestroyDB(dbname_, Options()); - delete tiny_cache_; - } - - Status TryReopen(Options* options = NULL) { - delete db_; - db_ = NULL; - Options opt = (options ? *options : options_); - opt.env = &env_; - opt.block_cache = tiny_cache_; - return DB::Open(opt, dbname_, &db_); - } - - void Reopen(Options* options = NULL) { - ASSERT_OK(TryReopen(options)); - } - - void RepairDB() { - delete db_; - db_ = NULL; - ASSERT_OK(::leveldb::RepairDB(dbname_, options_)); - } - - void Build(int n) { - std::string key_space, value_space; - WriteBatch batch; - for (int i = 0; i < n; i++) { - //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n); - Slice key = Key(i, &key_space); - batch.Clear(); - batch.Put(key, Value(i, &value_space)); - ASSERT_OK(db_->Write(WriteOptions(), &batch)); - } - } - - void Check(int min_expected, int max_expected) { - int next_expected = 0; - int missed = 0; - int bad_keys = 0; - int bad_values = 0; - int correct = 0; - std::string value_space; - Iterator* iter = db_->NewIterator(ReadOptions()); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - uint64_t key; - Slice in(iter->key()); - if (!ConsumeDecimalNumber(&in, &key) || - !in.empty() || - key < next_expected) { - bad_keys++; - continue; - } - missed += (key - next_expected); - next_expected = key + 1; - if (iter->value() != Value(key, &value_space)) { - bad_values++; - } else { - correct++; - } - } - delete iter; - - fprintf(stderr, - "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n", - min_expected, max_expected, correct, bad_keys, bad_values, missed); - ASSERT_LE(min_expected, correct); - ASSERT_GE(max_expected, correct); - } - - void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) { - // Pick file to corrupt - std::vector filenames; - ASSERT_OK(env_.GetChildren(dbname_, &filenames)); - uint64_t number; - FileType type; - std::string fname; - int picked_number = -1; - for (int i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) && - type == filetype && - int(number) > picked_number) { // Pick latest file - fname = dbname_ + "/" + filenames[i]; - picked_number = number; - } - } - ASSERT_TRUE(!fname.empty()) << filetype; - - struct stat sbuf; - if (stat(fname.c_str(), &sbuf) != 0) { - const char* msg = strerror(errno); - ASSERT_TRUE(false) << fname << ": " << msg; - } - - if (offset < 0) { - // Relative to end of file; make it absolute - if (-offset > sbuf.st_size) { - offset = 0; - } else { - offset = sbuf.st_size + offset; - } - } - if (offset > sbuf.st_size) { - offset = sbuf.st_size; - } - if (offset + bytes_to_corrupt > sbuf.st_size) { - bytes_to_corrupt = sbuf.st_size - offset; - } - - // Do it - std::string contents; - Status s = ReadFileToString(Env::Default(), fname, &contents); - ASSERT_TRUE(s.ok()) << s.ToString(); - for (int i = 0; i < bytes_to_corrupt; i++) { - contents[i + offset] ^= 0x80; - } - s = WriteStringToFile(Env::Default(), contents, fname); - ASSERT_TRUE(s.ok()) << s.ToString(); - } - - int Property(const std::string& name) { - std::string property; - int result; - if (db_->GetProperty(name, &property) && - sscanf(property.c_str(), "%d", &result) == 1) { - return result; - } else { - return -1; - } - } - - // Return the ith key - Slice Key(int i, std::string* storage) { - char buf[100]; - snprintf(buf, sizeof(buf), "%016d", i); - storage->assign(buf, strlen(buf)); - return Slice(*storage); - } - - // Return the value to associate with the specified key - Slice Value(int k, std::string* storage) { - Random r(k); - return test::RandomString(&r, kValueSize, storage); - } -}; - -TEST(CorruptionTest, Recovery) { - Build(100); - Check(100, 100); - Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record - Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block - Reopen(); - - // The 64 records in the first two log blocks are completely lost. - Check(36, 36); -} - -TEST(CorruptionTest, RecoverWriteError) { - env_.writable_file_error_ = true; - Status s = TryReopen(); - ASSERT_TRUE(!s.ok()); -} - -TEST(CorruptionTest, NewFileErrorDuringWrite) { - // Do enough writing to force minor compaction - env_.writable_file_error_ = true; - const int num = 3 + (Options().write_buffer_size / kValueSize); - std::string value_storage; - Status s; - for (int i = 0; s.ok() && i < num; i++) { - WriteBatch batch; - batch.Put("a", Value(100, &value_storage)); - s = db_->Write(WriteOptions(), &batch); - } - ASSERT_TRUE(!s.ok()); - ASSERT_GE(env_.num_writable_file_errors_, 1); - env_.writable_file_error_ = false; - Reopen(); -} - -TEST(CorruptionTest, TableFile) { - Build(100); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - dbi->TEST_CompactRange(0, NULL, NULL); - dbi->TEST_CompactRange(1, NULL, NULL); - - Corrupt(kTableFile, 100, 1); - Check(99, 99); -} - -TEST(CorruptionTest, TableFileIndexData) { - Build(10000); // Enough to build multiple Tables - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - - Corrupt(kTableFile, -2000, 500); - Reopen(); - Check(5000, 9999); -} - -TEST(CorruptionTest, MissingDescriptor) { - Build(1000); - RepairDB(); - Reopen(); - Check(1000, 1000); -} - -TEST(CorruptionTest, SequenceNumberRecovery) { - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5")); - RepairDB(); - Reopen(); - std::string v; - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("v5", v); - // Write something. If sequence number was not recovered properly, - // it will be hidden by an earlier write. - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6")); - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("v6", v); - Reopen(); - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("v6", v); -} - -TEST(CorruptionTest, CorruptedDescriptor) { - ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - dbi->TEST_CompactRange(0, NULL, NULL); - - Corrupt(kDescriptorFile, 0, 1000); - Status s = TryReopen(); - ASSERT_TRUE(!s.ok()); - - RepairDB(); - Reopen(); - std::string v; - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("hello", v); -} - -TEST(CorruptionTest, CompactionInputError) { - Build(10); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); - - Corrupt(kTableFile, 100, 1); - Check(9, 9); - - // Force compactions by writing lots of values - Build(10000); - Check(10000, 10000); -} - -TEST(CorruptionTest, CompactionInputErrorParanoid) { - Options options; - options.paranoid_checks = true; - options.write_buffer_size = 1048576; - Reopen(&options); - DBImpl* dbi = reinterpret_cast(db_); - - // Fill levels >= 1 so memtable compaction outputs to level 1 - for (int level = 1; level < config::kNumLevels; level++) { - dbi->Put(WriteOptions(), "", "begin"); - dbi->Put(WriteOptions(), "~", "end"); - dbi->TEST_CompactMemTable(); - } - - Build(10); - dbi->TEST_CompactMemTable(); - ASSERT_EQ(1, Property("leveldb.num-files-at-level0")); - - Corrupt(kTableFile, 100, 1); - Check(9, 9); - - // Write must eventually fail because of corrupted table - Status s; - std::string tmp1, tmp2; - for (int i = 0; i < 10000 && s.ok(); i++) { - s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2)); - } - ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; -} - -TEST(CorruptionTest, UnrelatedKeys) { - Build(10); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - Corrupt(kTableFile, 100, 1); - - std::string tmp1, tmp2; - ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2))); - std::string v; - ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); - ASSERT_EQ(Value(1000, &tmp2).ToString(), v); - dbi->TEST_CompactMemTable(); - ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); - ASSERT_EQ(Value(1000, &tmp2).ToString(), v); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc deleted file mode 100644 index 7abdf8758..000000000 --- a/src/leveldb/db/db_bench.cc +++ /dev/null @@ -1,979 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include -#include "db/db_impl.h" -#include "db/version_set.h" -#include "leveldb/cache.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/write_batch.h" -#include "port/port.h" -#include "util/crc32c.h" -#include "util/histogram.h" -#include "util/mutexlock.h" -#include "util/random.h" -#include "util/testutil.h" - -// Comma-separated list of operations to run in the specified order -// Actual benchmarks: -// fillseq -- write N values in sequential key order in async mode -// fillrandom -- write N values in random key order in async mode -// overwrite -- overwrite N values in random key order in async mode -// fillsync -- write N/100 values in random key order in sync mode -// fill100K -- write N/1000 100K values in random order in async mode -// deleteseq -- delete N keys in sequential order -// deleterandom -- delete N keys in random order -// readseq -- read N times sequentially -// readreverse -- read N times in reverse order -// readrandom -- read N times in random order -// readmissing -- read N missing keys in random order -// readhot -- read N times in random order from 1% section of DB -// seekrandom -- N random seeks -// crc32c -- repeated crc32c of 4K of data -// acquireload -- load N*1000 times -// Meta operations: -// compact -- Compact the entire DB -// stats -- Print DB stats -// sstables -- Print sstable info -// heapprofile -- Dump a heap profile (if supported by this port) -static const char* FLAGS_benchmarks = - "fillseq," - "fillsync," - "fillrandom," - "overwrite," - "readrandom," - "readrandom," // Extra run to allow previous compactions to quiesce - "readseq," - "readreverse," - "compact," - "readrandom," - "readseq," - "readreverse," - "fill100K," - "crc32c," - "snappycomp," - "snappyuncomp," - "acquireload," - ; - -// Number of key/values to place in database -static int FLAGS_num = 1000000; - -// Number of read operations to do. If negative, do FLAGS_num reads. -static int FLAGS_reads = -1; - -// Number of concurrent threads to run. -static int FLAGS_threads = 1; - -// Size of each value -static int FLAGS_value_size = 100; - -// Arrange to generate values that shrink to this fraction of -// their original size after compression -static double FLAGS_compression_ratio = 0.5; - -// Print histogram of operation timings -static bool FLAGS_histogram = false; - -// Number of bytes to buffer in memtable before compacting -// (initialized to default value by "main") -static int FLAGS_write_buffer_size = 0; - -// Number of bytes to use as a cache of uncompressed data. -// Negative means use default settings. -static int FLAGS_cache_size = -1; - -// Maximum number of files to keep open at the same time (use default if == 0) -static int FLAGS_open_files = 0; - -// Bloom filter bits per key. -// Negative means use default settings. -static int FLAGS_bloom_bits = -1; - -// If true, do not destroy the existing database. If you set this -// flag and also specify a benchmark that wants a fresh database, that -// benchmark will fail. -static bool FLAGS_use_existing_db = false; - -// Use the db with the following name. -static const char* FLAGS_db = NULL; - -namespace leveldb { - -namespace { - -// Helper for quickly generating random data. -class RandomGenerator { - private: - std::string data_; - int pos_; - - public: - RandomGenerator() { - // We use a limited amount of data over and over again and ensure - // that it is larger than the compression window (32KB), and also - // large enough to serve all typical value sizes we want to write. - Random rnd(301); - std::string piece; - while (data_.size() < 1048576) { - // Add a short fragment that is as compressible as specified - // by FLAGS_compression_ratio. - test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); - data_.append(piece); - } - pos_ = 0; - } - - Slice Generate(int len) { - if (pos_ + len > data_.size()) { - pos_ = 0; - assert(len < data_.size()); - } - pos_ += len; - return Slice(data_.data() + pos_ - len, len); - } -}; - -static Slice TrimSpace(Slice s) { - int start = 0; - while (start < s.size() && isspace(s[start])) { - start++; - } - int limit = s.size(); - while (limit > start && isspace(s[limit-1])) { - limit--; - } - return Slice(s.data() + start, limit - start); -} - -static void AppendWithSpace(std::string* str, Slice msg) { - if (msg.empty()) return; - if (!str->empty()) { - str->push_back(' '); - } - str->append(msg.data(), msg.size()); -} - -class Stats { - private: - double start_; - double finish_; - double seconds_; - int done_; - int next_report_; - int64_t bytes_; - double last_op_finish_; - Histogram hist_; - std::string message_; - - public: - Stats() { Start(); } - - void Start() { - next_report_ = 100; - last_op_finish_ = start_; - hist_.Clear(); - done_ = 0; - bytes_ = 0; - seconds_ = 0; - start_ = Env::Default()->NowMicros(); - finish_ = start_; - message_.clear(); - } - - void Merge(const Stats& other) { - hist_.Merge(other.hist_); - done_ += other.done_; - bytes_ += other.bytes_; - seconds_ += other.seconds_; - if (other.start_ < start_) start_ = other.start_; - if (other.finish_ > finish_) finish_ = other.finish_; - - // Just keep the messages from one thread - if (message_.empty()) message_ = other.message_; - } - - void Stop() { - finish_ = Env::Default()->NowMicros(); - seconds_ = (finish_ - start_) * 1e-6; - } - - void AddMessage(Slice msg) { - AppendWithSpace(&message_, msg); - } - - void FinishedSingleOp() { - if (FLAGS_histogram) { - double now = Env::Default()->NowMicros(); - double micros = now - last_op_finish_; - hist_.Add(micros); - if (micros > 20000) { - fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); - fflush(stderr); - } - last_op_finish_ = now; - } - - done_++; - if (done_ >= next_report_) { - if (next_report_ < 1000) next_report_ += 100; - else if (next_report_ < 5000) next_report_ += 500; - else if (next_report_ < 10000) next_report_ += 1000; - else if (next_report_ < 50000) next_report_ += 5000; - else if (next_report_ < 100000) next_report_ += 10000; - else if (next_report_ < 500000) next_report_ += 50000; - else next_report_ += 100000; - fprintf(stderr, "... finished %d ops%30s\r", done_, ""); - fflush(stderr); - } - } - - void AddBytes(int64_t n) { - bytes_ += n; - } - - void Report(const Slice& name) { - // Pretend at least one op was done in case we are running a benchmark - // that does not call FinishedSingleOp(). - if (done_ < 1) done_ = 1; - - std::string extra; - if (bytes_ > 0) { - // Rate is computed on actual elapsed time, not the sum of per-thread - // elapsed times. - double elapsed = (finish_ - start_) * 1e-6; - char rate[100]; - snprintf(rate, sizeof(rate), "%6.1f MB/s", - (bytes_ / 1048576.0) / elapsed); - extra = rate; - } - AppendWithSpace(&extra, message_); - - fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", - name.ToString().c_str(), - seconds_ * 1e6 / done_, - (extra.empty() ? "" : " "), - extra.c_str()); - if (FLAGS_histogram) { - fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); - } - fflush(stdout); - } -}; - -// State shared by all concurrent executions of the same benchmark. -struct SharedState { - port::Mutex mu; - port::CondVar cv; - int total; - - // Each thread goes through the following states: - // (1) initializing - // (2) waiting for others to be initialized - // (3) running - // (4) done - - int num_initialized; - int num_done; - bool start; - - SharedState() : cv(&mu) { } -}; - -// Per-thread state for concurrent executions of the same benchmark. -struct ThreadState { - int tid; // 0..n-1 when running in n threads - Random rand; // Has different seeds for different threads - Stats stats; - SharedState* shared; - - ThreadState(int index) - : tid(index), - rand(1000 + index) { - } -}; - -} // namespace - -class Benchmark { - private: - Cache* cache_; - const FilterPolicy* filter_policy_; - DB* db_; - int num_; - int value_size_; - int entries_per_batch_; - WriteOptions write_options_; - int reads_; - int heap_counter_; - - void PrintHeader() { - const int kKeySize = 16; - PrintEnvironment(); - fprintf(stdout, "Keys: %d bytes each\n", kKeySize); - fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", - FLAGS_value_size, - static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); - fprintf(stdout, "Entries: %d\n", num_); - fprintf(stdout, "RawSize: %.1f MB (estimated)\n", - ((static_cast(kKeySize + FLAGS_value_size) * num_) - / 1048576.0)); - fprintf(stdout, "FileSize: %.1f MB (estimated)\n", - (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) - / 1048576.0)); - PrintWarnings(); - fprintf(stdout, "------------------------------------------------\n"); - } - - void PrintWarnings() { -#if defined(__GNUC__) && !defined(__OPTIMIZE__) - fprintf(stdout, - "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" - ); -#endif -#ifndef NDEBUG - fprintf(stdout, - "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); -#endif - - // See if snappy is working by attempting to compress a compressible string - const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; - std::string compressed; - if (!port::Snappy_Compress(text, sizeof(text), &compressed)) { - fprintf(stdout, "WARNING: Snappy compression is not enabled\n"); - } else if (compressed.size() >= sizeof(text)) { - fprintf(stdout, "WARNING: Snappy compression is not effective\n"); - } - } - - void PrintEnvironment() { - fprintf(stderr, "LevelDB: version %d.%d\n", - kMajorVersion, kMinorVersion); - -#if defined(__linux) - time_t now = time(NULL); - fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline - - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if (cpuinfo != NULL) { - char line[1000]; - int num_cpus = 0; - std::string cpu_type; - std::string cache_size; - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - const char* sep = strchr(line, ':'); - if (sep == NULL) { - continue; - } - Slice key = TrimSpace(Slice(line, sep - 1 - line)); - Slice val = TrimSpace(Slice(sep + 1)); - if (key == "model name") { - ++num_cpus; - cpu_type = val.ToString(); - } else if (key == "cache size") { - cache_size = val.ToString(); - } - } - fclose(cpuinfo); - fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); - fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); - } -#endif - } - - public: - Benchmark() - : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL), - filter_policy_(FLAGS_bloom_bits >= 0 - ? NewBloomFilterPolicy(FLAGS_bloom_bits) - : NULL), - db_(NULL), - num_(FLAGS_num), - value_size_(FLAGS_value_size), - entries_per_batch_(1), - reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), - heap_counter_(0) { - std::vector files; - Env::Default()->GetChildren(FLAGS_db, &files); - for (int i = 0; i < files.size(); i++) { - if (Slice(files[i]).starts_with("heap-")) { - Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); - } - } - if (!FLAGS_use_existing_db) { - DestroyDB(FLAGS_db, Options()); - } - } - - ~Benchmark() { - delete db_; - delete cache_; - delete filter_policy_; - } - - void Run() { - PrintHeader(); - Open(); - - const char* benchmarks = FLAGS_benchmarks; - while (benchmarks != NULL) { - const char* sep = strchr(benchmarks, ','); - Slice name; - if (sep == NULL) { - name = benchmarks; - benchmarks = NULL; - } else { - name = Slice(benchmarks, sep - benchmarks); - benchmarks = sep + 1; - } - - // Reset parameters that may be overriddden bwlow - num_ = FLAGS_num; - reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads); - value_size_ = FLAGS_value_size; - entries_per_batch_ = 1; - write_options_ = WriteOptions(); - - void (Benchmark::*method)(ThreadState*) = NULL; - bool fresh_db = false; - int num_threads = FLAGS_threads; - - if (name == Slice("fillseq")) { - fresh_db = true; - method = &Benchmark::WriteSeq; - } else if (name == Slice("fillbatch")) { - fresh_db = true; - entries_per_batch_ = 1000; - method = &Benchmark::WriteSeq; - } else if (name == Slice("fillrandom")) { - fresh_db = true; - method = &Benchmark::WriteRandom; - } else if (name == Slice("overwrite")) { - fresh_db = false; - method = &Benchmark::WriteRandom; - } else if (name == Slice("fillsync")) { - fresh_db = true; - num_ /= 1000; - write_options_.sync = true; - method = &Benchmark::WriteRandom; - } else if (name == Slice("fill100K")) { - fresh_db = true; - num_ /= 1000; - value_size_ = 100 * 1000; - method = &Benchmark::WriteRandom; - } else if (name == Slice("readseq")) { - method = &Benchmark::ReadSequential; - } else if (name == Slice("readreverse")) { - method = &Benchmark::ReadReverse; - } else if (name == Slice("readrandom")) { - method = &Benchmark::ReadRandom; - } else if (name == Slice("readmissing")) { - method = &Benchmark::ReadMissing; - } else if (name == Slice("seekrandom")) { - method = &Benchmark::SeekRandom; - } else if (name == Slice("readhot")) { - method = &Benchmark::ReadHot; - } else if (name == Slice("readrandomsmall")) { - reads_ /= 1000; - method = &Benchmark::ReadRandom; - } else if (name == Slice("deleteseq")) { - method = &Benchmark::DeleteSeq; - } else if (name == Slice("deleterandom")) { - method = &Benchmark::DeleteRandom; - } else if (name == Slice("readwhilewriting")) { - num_threads++; // Add extra thread for writing - method = &Benchmark::ReadWhileWriting; - } else if (name == Slice("compact")) { - method = &Benchmark::Compact; - } else if (name == Slice("crc32c")) { - method = &Benchmark::Crc32c; - } else if (name == Slice("acquireload")) { - method = &Benchmark::AcquireLoad; - } else if (name == Slice("snappycomp")) { - method = &Benchmark::SnappyCompress; - } else if (name == Slice("snappyuncomp")) { - method = &Benchmark::SnappyUncompress; - } else if (name == Slice("heapprofile")) { - HeapProfile(); - } else if (name == Slice("stats")) { - PrintStats("leveldb.stats"); - } else if (name == Slice("sstables")) { - PrintStats("leveldb.sstables"); - } else { - if (name != Slice()) { // No error message for empty name - fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); - } - } - - if (fresh_db) { - if (FLAGS_use_existing_db) { - fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n", - name.ToString().c_str()); - method = NULL; - } else { - delete db_; - db_ = NULL; - DestroyDB(FLAGS_db, Options()); - Open(); - } - } - - if (method != NULL) { - RunBenchmark(num_threads, name, method); - } - } - } - - private: - struct ThreadArg { - Benchmark* bm; - SharedState* shared; - ThreadState* thread; - void (Benchmark::*method)(ThreadState*); - }; - - static void ThreadBody(void* v) { - ThreadArg* arg = reinterpret_cast(v); - SharedState* shared = arg->shared; - ThreadState* thread = arg->thread; - { - MutexLock l(&shared->mu); - shared->num_initialized++; - if (shared->num_initialized >= shared->total) { - shared->cv.SignalAll(); - } - while (!shared->start) { - shared->cv.Wait(); - } - } - - thread->stats.Start(); - (arg->bm->*(arg->method))(thread); - thread->stats.Stop(); - - { - MutexLock l(&shared->mu); - shared->num_done++; - if (shared->num_done >= shared->total) { - shared->cv.SignalAll(); - } - } - } - - void RunBenchmark(int n, Slice name, - void (Benchmark::*method)(ThreadState*)) { - SharedState shared; - shared.total = n; - shared.num_initialized = 0; - shared.num_done = 0; - shared.start = false; - - ThreadArg* arg = new ThreadArg[n]; - for (int i = 0; i < n; i++) { - arg[i].bm = this; - arg[i].method = method; - arg[i].shared = &shared; - arg[i].thread = new ThreadState(i); - arg[i].thread->shared = &shared; - Env::Default()->StartThread(ThreadBody, &arg[i]); - } - - shared.mu.Lock(); - while (shared.num_initialized < n) { - shared.cv.Wait(); - } - - shared.start = true; - shared.cv.SignalAll(); - while (shared.num_done < n) { - shared.cv.Wait(); - } - shared.mu.Unlock(); - - for (int i = 1; i < n; i++) { - arg[0].thread->stats.Merge(arg[i].thread->stats); - } - arg[0].thread->stats.Report(name); - - for (int i = 0; i < n; i++) { - delete arg[i].thread; - } - delete[] arg; - } - - void Crc32c(ThreadState* thread) { - // Checksum about 500MB of data total - const int size = 4096; - const char* label = "(4K per op)"; - std::string data(size, 'x'); - int64_t bytes = 0; - uint32_t crc = 0; - while (bytes < 500 * 1048576) { - crc = crc32c::Value(data.data(), size); - thread->stats.FinishedSingleOp(); - bytes += size; - } - // Print so result is not dead - fprintf(stderr, "... crc=0x%x\r", static_cast(crc)); - - thread->stats.AddBytes(bytes); - thread->stats.AddMessage(label); - } - - void AcquireLoad(ThreadState* thread) { - int dummy; - port::AtomicPointer ap(&dummy); - int count = 0; - void *ptr = NULL; - thread->stats.AddMessage("(each op is 1000 loads)"); - while (count < 100000) { - for (int i = 0; i < 1000; i++) { - ptr = ap.Acquire_Load(); - } - count++; - thread->stats.FinishedSingleOp(); - } - if (ptr == NULL) exit(1); // Disable unused variable warning. - } - - void SnappyCompress(ThreadState* thread) { - RandomGenerator gen; - Slice input = gen.Generate(Options().block_size); - int64_t bytes = 0; - int64_t produced = 0; - bool ok = true; - std::string compressed; - while (ok && bytes < 1024 * 1048576) { // Compress 1G - ok = port::Snappy_Compress(input.data(), input.size(), &compressed); - produced += compressed.size(); - bytes += input.size(); - thread->stats.FinishedSingleOp(); - } - - if (!ok) { - thread->stats.AddMessage("(snappy failure)"); - } else { - char buf[100]; - snprintf(buf, sizeof(buf), "(output: %.1f%%)", - (produced * 100.0) / bytes); - thread->stats.AddMessage(buf); - thread->stats.AddBytes(bytes); - } - } - - void SnappyUncompress(ThreadState* thread) { - RandomGenerator gen; - Slice input = gen.Generate(Options().block_size); - std::string compressed; - bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed); - int64_t bytes = 0; - char* uncompressed = new char[input.size()]; - while (ok && bytes < 1024 * 1048576) { // Compress 1G - ok = port::Snappy_Uncompress(compressed.data(), compressed.size(), - uncompressed); - bytes += input.size(); - thread->stats.FinishedSingleOp(); - } - delete[] uncompressed; - - if (!ok) { - thread->stats.AddMessage("(snappy failure)"); - } else { - thread->stats.AddBytes(bytes); - } - } - - void Open() { - assert(db_ == NULL); - Options options; - options.create_if_missing = !FLAGS_use_existing_db; - options.block_cache = cache_; - options.write_buffer_size = FLAGS_write_buffer_size; - options.max_open_files = FLAGS_open_files; - options.filter_policy = filter_policy_; - Status s = DB::Open(options, FLAGS_db, &db_); - if (!s.ok()) { - fprintf(stderr, "open error: %s\n", s.ToString().c_str()); - exit(1); - } - } - - void WriteSeq(ThreadState* thread) { - DoWrite(thread, true); - } - - void WriteRandom(ThreadState* thread) { - DoWrite(thread, false); - } - - void DoWrite(ThreadState* thread, bool seq) { - if (num_ != FLAGS_num) { - char msg[100]; - snprintf(msg, sizeof(msg), "(%d ops)", num_); - thread->stats.AddMessage(msg); - } - - RandomGenerator gen; - WriteBatch batch; - Status s; - int64_t bytes = 0; - for (int i = 0; i < num_; i += entries_per_batch_) { - batch.Clear(); - for (int j = 0; j < entries_per_batch_; j++) { - const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - batch.Put(key, gen.Generate(value_size_)); - bytes += value_size_ + strlen(key); - thread->stats.FinishedSingleOp(); - } - s = db_->Write(write_options_, &batch); - if (!s.ok()) { - fprintf(stderr, "put error: %s\n", s.ToString().c_str()); - exit(1); - } - } - thread->stats.AddBytes(bytes); - } - - void ReadSequential(ThreadState* thread) { - Iterator* iter = db_->NewIterator(ReadOptions()); - int i = 0; - int64_t bytes = 0; - for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) { - bytes += iter->key().size() + iter->value().size(); - thread->stats.FinishedSingleOp(); - ++i; - } - delete iter; - thread->stats.AddBytes(bytes); - } - - void ReadReverse(ThreadState* thread) { - Iterator* iter = db_->NewIterator(ReadOptions()); - int i = 0; - int64_t bytes = 0; - for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) { - bytes += iter->key().size() + iter->value().size(); - thread->stats.FinishedSingleOp(); - ++i; - } - delete iter; - thread->stats.AddBytes(bytes); - } - - void ReadRandom(ThreadState* thread) { - ReadOptions options; - std::string value; - int found = 0; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = thread->rand.Next() % FLAGS_num; - snprintf(key, sizeof(key), "%016d", k); - if (db_->Get(options, key, &value).ok()) { - found++; - } - thread->stats.FinishedSingleOp(); - } - char msg[100]; - snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); - thread->stats.AddMessage(msg); - } - - void ReadMissing(ThreadState* thread) { - ReadOptions options; - std::string value; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = thread->rand.Next() % FLAGS_num; - snprintf(key, sizeof(key), "%016d.", k); - db_->Get(options, key, &value); - thread->stats.FinishedSingleOp(); - } - } - - void ReadHot(ThreadState* thread) { - ReadOptions options; - std::string value; - const int range = (FLAGS_num + 99) / 100; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = thread->rand.Next() % range; - snprintf(key, sizeof(key), "%016d", k); - db_->Get(options, key, &value); - thread->stats.FinishedSingleOp(); - } - } - - void SeekRandom(ThreadState* thread) { - ReadOptions options; - std::string value; - int found = 0; - for (int i = 0; i < reads_; i++) { - Iterator* iter = db_->NewIterator(options); - char key[100]; - const int k = thread->rand.Next() % FLAGS_num; - snprintf(key, sizeof(key), "%016d", k); - iter->Seek(key); - if (iter->Valid() && iter->key() == key) found++; - delete iter; - thread->stats.FinishedSingleOp(); - } - char msg[100]; - snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); - thread->stats.AddMessage(msg); - } - - void DoDelete(ThreadState* thread, bool seq) { - RandomGenerator gen; - WriteBatch batch; - Status s; - for (int i = 0; i < num_; i += entries_per_batch_) { - batch.Clear(); - for (int j = 0; j < entries_per_batch_; j++) { - const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - batch.Delete(key); - thread->stats.FinishedSingleOp(); - } - s = db_->Write(write_options_, &batch); - if (!s.ok()) { - fprintf(stderr, "del error: %s\n", s.ToString().c_str()); - exit(1); - } - } - } - - void DeleteSeq(ThreadState* thread) { - DoDelete(thread, true); - } - - void DeleteRandom(ThreadState* thread) { - DoDelete(thread, false); - } - - void ReadWhileWriting(ThreadState* thread) { - if (thread->tid > 0) { - ReadRandom(thread); - } else { - // Special thread that keeps writing until other threads are done. - RandomGenerator gen; - while (true) { - { - MutexLock l(&thread->shared->mu); - if (thread->shared->num_done + 1 >= thread->shared->num_initialized) { - // Other threads have finished - break; - } - } - - const int k = thread->rand.Next() % FLAGS_num; - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - Status s = db_->Put(write_options_, key, gen.Generate(value_size_)); - if (!s.ok()) { - fprintf(stderr, "put error: %s\n", s.ToString().c_str()); - exit(1); - } - } - - // Do not count any of the preceding work/delay in stats. - thread->stats.Start(); - } - } - - void Compact(ThreadState* thread) { - db_->CompactRange(NULL, NULL); - } - - void PrintStats(const char* key) { - std::string stats; - if (!db_->GetProperty(key, &stats)) { - stats = "(failed)"; - } - fprintf(stdout, "\n%s\n", stats.c_str()); - } - - static void WriteToFile(void* arg, const char* buf, int n) { - reinterpret_cast(arg)->Append(Slice(buf, n)); - } - - void HeapProfile() { - char fname[100]; - snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); - WritableFile* file; - Status s = Env::Default()->NewWritableFile(fname, &file); - if (!s.ok()) { - fprintf(stderr, "%s\n", s.ToString().c_str()); - return; - } - bool ok = port::GetHeapProfile(WriteToFile, file); - delete file; - if (!ok) { - fprintf(stderr, "heap profiling not supported\n"); - Env::Default()->DeleteFile(fname); - } - } -}; - -} // namespace leveldb - -int main(int argc, char** argv) { - FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; - FLAGS_open_files = leveldb::Options().max_open_files; - std::string default_db_path; - - for (int i = 1; i < argc; i++) { - double d; - int n; - char junk; - if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { - FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); - } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { - FLAGS_compression_ratio = d; - } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_histogram = n; - } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_use_existing_db = n; - } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { - FLAGS_num = n; - } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { - FLAGS_reads = n; - } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) { - FLAGS_threads = n; - } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { - FLAGS_value_size = n; - } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { - FLAGS_write_buffer_size = n; - } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { - FLAGS_cache_size = n; - } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { - FLAGS_bloom_bits = n; - } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) { - FLAGS_open_files = n; - } else if (strncmp(argv[i], "--db=", 5) == 0) { - FLAGS_db = argv[i] + 5; - } else { - fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - exit(1); - } - } - - // Choose a location for the test database if none given with --db= - if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); - default_db_path += "/dbbench"; - FLAGS_db = default_db_path.c_str(); - } - - leveldb::Benchmark benchmark; - benchmark.Run(); - return 0; -} diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc deleted file mode 100644 index c9de169f2..000000000 --- a/src/leveldb/db/db_impl.cc +++ /dev/null @@ -1,1467 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/db_impl.h" - -#include -#include -#include -#include -#include -#include -#include "db/builder.h" -#include "db/db_iter.h" -#include "db/dbformat.h" -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "db/memtable.h" -#include "db/table_cache.h" -#include "db/version_set.h" -#include "db/write_batch_internal.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/status.h" -#include "leveldb/table.h" -#include "leveldb/table_builder.h" -#include "port/port.h" -#include "table/block.h" -#include "table/merger.h" -#include "table/two_level_iterator.h" -#include "util/coding.h" -#include "util/logging.h" -#include "util/mutexlock.h" - -namespace leveldb { - -// Information kept for every waiting writer -struct DBImpl::Writer { - Status status; - WriteBatch* batch; - bool sync; - bool done; - port::CondVar cv; - - explicit Writer(port::Mutex* mu) : cv(mu) { } -}; - -struct DBImpl::CompactionState { - Compaction* const compaction; - - // Sequence numbers < smallest_snapshot are not significant since we - // will never have to service a snapshot below smallest_snapshot. - // Therefore if we have seen a sequence number S <= smallest_snapshot, - // we can drop all entries for the same key with sequence numbers < S. - SequenceNumber smallest_snapshot; - - // Files produced by compaction - struct Output { - uint64_t number; - uint64_t file_size; - InternalKey smallest, largest; - }; - std::vector outputs; - - // State kept for output being generated - WritableFile* outfile; - TableBuilder* builder; - - uint64_t total_bytes; - - Output* current_output() { return &outputs[outputs.size()-1]; } - - explicit CompactionState(Compaction* c) - : compaction(c), - outfile(NULL), - builder(NULL), - total_bytes(0) { - } -}; - -// Fix user-supplied options to be reasonable -template -static void ClipToRange(T* ptr, V minvalue, V maxvalue) { - if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; - if (static_cast(*ptr) < minvalue) *ptr = minvalue; -} -Options SanitizeOptions(const std::string& dbname, - const InternalKeyComparator* icmp, - const InternalFilterPolicy* ipolicy, - const Options& src) { - Options result = src; - result.comparator = icmp; - result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; - ClipToRange(&result.max_open_files, 20, 50000); - ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); - ClipToRange(&result.block_size, 1<<10, 4<<20); - if (result.info_log == NULL) { - // Open a log file in the same directory as the db - src.env->CreateDir(dbname); // In case it does not exist - src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); - Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); - if (!s.ok()) { - // No place suitable for logging - result.info_log = NULL; - } - } - if (result.block_cache == NULL) { - result.block_cache = NewLRUCache(8 << 20); - } - return result; -} - -DBImpl::DBImpl(const Options& options, const std::string& dbname) - : env_(options.env), - internal_comparator_(options.comparator), - internal_filter_policy_(options.filter_policy), - options_(SanitizeOptions( - dbname, &internal_comparator_, &internal_filter_policy_, options)), - owns_info_log_(options_.info_log != options.info_log), - owns_cache_(options_.block_cache != options.block_cache), - dbname_(dbname), - db_lock_(NULL), - shutting_down_(NULL), - bg_cv_(&mutex_), - mem_(new MemTable(internal_comparator_)), - imm_(NULL), - logfile_(NULL), - logfile_number_(0), - log_(NULL), - tmp_batch_(new WriteBatch), - bg_compaction_scheduled_(false), - manual_compaction_(NULL) { - mem_->Ref(); - has_imm_.Release_Store(NULL); - - // Reserve ten files or so for other uses and give the rest to TableCache. - const int table_cache_size = options.max_open_files - 10; - table_cache_ = new TableCache(dbname_, &options_, table_cache_size); - - versions_ = new VersionSet(dbname_, &options_, table_cache_, - &internal_comparator_); -} - -DBImpl::~DBImpl() { - // Wait for background work to finish - mutex_.Lock(); - shutting_down_.Release_Store(this); // Any non-NULL value is ok - while (bg_compaction_scheduled_) { - bg_cv_.Wait(); - } - mutex_.Unlock(); - - if (db_lock_ != NULL) { - env_->UnlockFile(db_lock_); - } - - delete versions_; - if (mem_ != NULL) mem_->Unref(); - if (imm_ != NULL) imm_->Unref(); - delete tmp_batch_; - delete log_; - delete logfile_; - delete table_cache_; - - if (owns_info_log_) { - delete options_.info_log; - } - if (owns_cache_) { - delete options_.block_cache; - } -} - -Status DBImpl::NewDB() { - VersionEdit new_db; - new_db.SetComparatorName(user_comparator()->Name()); - new_db.SetLogNumber(0); - new_db.SetNextFile(2); - new_db.SetLastSequence(0); - - const std::string manifest = DescriptorFileName(dbname_, 1); - WritableFile* file; - Status s = env_->NewWritableFile(manifest, &file); - if (!s.ok()) { - return s; - } - { - log::Writer log(file); - std::string record; - new_db.EncodeTo(&record); - s = log.AddRecord(record); - if (s.ok()) { - s = file->Close(); - } - } - delete file; - if (s.ok()) { - // Make "CURRENT" file that points to the new manifest file. - s = SetCurrentFile(env_, dbname_, 1); - } else { - env_->DeleteFile(manifest); - } - return s; -} - -void DBImpl::MaybeIgnoreError(Status* s) const { - if (s->ok() || options_.paranoid_checks) { - // No change needed - } else { - Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); - *s = Status::OK(); - } -} - -void DBImpl::DeleteObsoleteFiles() { - // Make a set of all of the live files - std::set live = pending_outputs_; - versions_->AddLiveFiles(&live); - - std::vector filenames; - env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type)) { - bool keep = true; - switch (type) { - case kLogFile: - keep = ((number >= versions_->LogNumber()) || - (number == versions_->PrevLogNumber())); - break; - case kDescriptorFile: - // Keep my manifest file, and any newer incarnations' - // (in case there is a race that allows other incarnations) - keep = (number >= versions_->ManifestFileNumber()); - break; - case kTableFile: - keep = (live.find(number) != live.end()); - break; - case kTempFile: - // Any temp files that are currently being written to must - // be recorded in pending_outputs_, which is inserted into "live" - keep = (live.find(number) != live.end()); - break; - case kCurrentFile: - case kDBLockFile: - case kInfoLogFile: - keep = true; - break; - } - - if (!keep) { - if (type == kTableFile) { - table_cache_->Evict(number); - } - Log(options_.info_log, "Delete type=%d #%lld\n", - int(type), - static_cast(number)); - env_->DeleteFile(dbname_ + "/" + filenames[i]); - } - } - } -} - -Status DBImpl::Recover(VersionEdit* edit) { - mutex_.AssertHeld(); - - // Ignore error from CreateDir since the creation of the DB is - // committed only when the descriptor is created, and this directory - // may already exist from a previous failed creation attempt. - env_->CreateDir(dbname_); - assert(db_lock_ == NULL); - Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); - if (!s.ok()) { - return s; - } - - if (!env_->FileExists(CurrentFileName(dbname_))) { - if (options_.create_if_missing) { - s = NewDB(); - if (!s.ok()) { - return s; - } - } else { - return Status::InvalidArgument( - dbname_, "does not exist (create_if_missing is false)"); - } - } else { - if (options_.error_if_exists) { - return Status::InvalidArgument( - dbname_, "exists (error_if_exists is true)"); - } - } - - s = versions_->Recover(); - if (s.ok()) { - SequenceNumber max_sequence(0); - - // Recover from all newer log files than the ones named in the - // descriptor (new log files may have been added by the previous - // incarnation without registering them in the descriptor). - // - // Note that PrevLogNumber() is no longer used, but we pay - // attention to it in case we are recovering a database - // produced by an older version of leveldb. - const uint64_t min_log = versions_->LogNumber(); - const uint64_t prev_log = versions_->PrevLogNumber(); - std::vector filenames; - s = env_->GetChildren(dbname_, &filenames); - if (!s.ok()) { - return s; - } - uint64_t number; - FileType type; - std::vector logs; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) - && type == kLogFile - && ((number >= min_log) || (number == prev_log))) { - logs.push_back(number); - } - } - - // Recover in the order in which the logs were generated - std::sort(logs.begin(), logs.end()); - for (size_t i = 0; i < logs.size(); i++) { - s = RecoverLogFile(logs[i], edit, &max_sequence); - - // The previous incarnation may not have written any MANIFEST - // records after allocating this log number. So we manually - // update the file number allocation counter in VersionSet. - versions_->MarkFileNumberUsed(logs[i]); - } - - if (s.ok()) { - if (versions_->LastSequence() < max_sequence) { - versions_->SetLastSequence(max_sequence); - } - } - } - - return s; -} - -Status DBImpl::RecoverLogFile(uint64_t log_number, - VersionEdit* edit, - SequenceNumber* max_sequence) { - struct LogReporter : public log::Reader::Reporter { - Env* env; - Logger* info_log; - const char* fname; - Status* status; // NULL if options_.paranoid_checks==false - virtual void Corruption(size_t bytes, const Status& s) { - Log(info_log, "%s%s: dropping %d bytes; %s", - (this->status == NULL ? "(ignoring error) " : ""), - fname, static_cast(bytes), s.ToString().c_str()); - if (this->status != NULL && this->status->ok()) *this->status = s; - } - }; - - mutex_.AssertHeld(); - - // Open the log file - std::string fname = LogFileName(dbname_, log_number); - SequentialFile* file; - Status status = env_->NewSequentialFile(fname, &file); - if (!status.ok()) { - MaybeIgnoreError(&status); - return status; - } - - // Create the log reader. - LogReporter reporter; - reporter.env = env_; - reporter.info_log = options_.info_log; - reporter.fname = fname.c_str(); - reporter.status = (options_.paranoid_checks ? &status : NULL); - // We intentially make log::Reader do checksumming even if - // paranoid_checks==false so that corruptions cause entire commits - // to be skipped instead of propagating bad information (like overly - // large sequence numbers). - log::Reader reader(file, &reporter, true/*checksum*/, - 0/*initial_offset*/); - Log(options_.info_log, "Recovering log #%llu", - (unsigned long long) log_number); - - // Read all the records and add to a memtable - std::string scratch; - Slice record; - WriteBatch batch; - MemTable* mem = NULL; - while (reader.ReadRecord(&record, &scratch) && - status.ok()) { - if (record.size() < 12) { - reporter.Corruption( - record.size(), Status::Corruption("log record too small")); - continue; - } - WriteBatchInternal::SetContents(&batch, record); - - if (mem == NULL) { - mem = new MemTable(internal_comparator_); - mem->Ref(); - } - status = WriteBatchInternal::InsertInto(&batch, mem); - MaybeIgnoreError(&status); - if (!status.ok()) { - break; - } - const SequenceNumber last_seq = - WriteBatchInternal::Sequence(&batch) + - WriteBatchInternal::Count(&batch) - 1; - if (last_seq > *max_sequence) { - *max_sequence = last_seq; - } - - if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { - status = WriteLevel0Table(mem, edit, NULL); - if (!status.ok()) { - // Reflect errors immediately so that conditions like full - // file-systems cause the DB::Open() to fail. - break; - } - mem->Unref(); - mem = NULL; - } - } - - if (status.ok() && mem != NULL) { - status = WriteLevel0Table(mem, edit, NULL); - // Reflect errors immediately so that conditions like full - // file-systems cause the DB::Open() to fail. - } - - if (mem != NULL) mem->Unref(); - delete file; - return status; -} - -Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, - Version* base) { - mutex_.AssertHeld(); - const uint64_t start_micros = env_->NowMicros(); - FileMetaData meta; - meta.number = versions_->NewFileNumber(); - pending_outputs_.insert(meta.number); - Iterator* iter = mem->NewIterator(); - Log(options_.info_log, "Level-0 table #%llu: started", - (unsigned long long) meta.number); - - Status s; - { - mutex_.Unlock(); - s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); - mutex_.Lock(); - } - - Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", - (unsigned long long) meta.number, - (unsigned long long) meta.file_size, - s.ToString().c_str()); - delete iter; - pending_outputs_.erase(meta.number); - - - // Note that if file_size is zero, the file has been deleted and - // should not be added to the manifest. - int level = 0; - if (s.ok() && meta.file_size > 0) { - const Slice min_user_key = meta.smallest.user_key(); - const Slice max_user_key = meta.largest.user_key(); - if (base != NULL) { - level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); - } - edit->AddFile(level, meta.number, meta.file_size, - meta.smallest, meta.largest); - } - - CompactionStats stats; - stats.micros = env_->NowMicros() - start_micros; - stats.bytes_written = meta.file_size; - stats_[level].Add(stats); - return s; -} - -Status DBImpl::CompactMemTable() { - mutex_.AssertHeld(); - assert(imm_ != NULL); - - // Save the contents of the memtable as a new Table - VersionEdit edit; - Version* base = versions_->current(); - base->Ref(); - Status s = WriteLevel0Table(imm_, &edit, base); - base->Unref(); - - if (s.ok() && shutting_down_.Acquire_Load()) { - s = Status::IOError("Deleting DB during memtable compaction"); - } - - // Replace immutable memtable with the generated Table - if (s.ok()) { - edit.SetPrevLogNumber(0); - edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed - s = versions_->LogAndApply(&edit, &mutex_); - } - - if (s.ok()) { - // Commit to the new state - imm_->Unref(); - imm_ = NULL; - has_imm_.Release_Store(NULL); - DeleteObsoleteFiles(); - } - - return s; -} - -void DBImpl::CompactRange(const Slice* begin, const Slice* end) { - int max_level_with_files = 1; - { - MutexLock l(&mutex_); - Version* base = versions_->current(); - for (int level = 1; level < config::kNumLevels; level++) { - if (base->OverlapInLevel(level, begin, end)) { - max_level_with_files = level; - } - } - } - TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap - for (int level = 0; level < max_level_with_files; level++) { - TEST_CompactRange(level, begin, end); - } -} - -void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) { - assert(level >= 0); - assert(level + 1 < config::kNumLevels); - - InternalKey begin_storage, end_storage; - - ManualCompaction manual; - manual.level = level; - manual.done = false; - if (begin == NULL) { - manual.begin = NULL; - } else { - begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); - manual.begin = &begin_storage; - } - if (end == NULL) { - manual.end = NULL; - } else { - end_storage = InternalKey(*end, 0, static_cast(0)); - manual.end = &end_storage; - } - - MutexLock l(&mutex_); - while (!manual.done) { - while (manual_compaction_ != NULL) { - bg_cv_.Wait(); - } - manual_compaction_ = &manual; - MaybeScheduleCompaction(); - while (manual_compaction_ == &manual) { - bg_cv_.Wait(); - } - } -} - -Status DBImpl::TEST_CompactMemTable() { - // NULL batch means just wait for earlier writes to be done - Status s = Write(WriteOptions(), NULL); - if (s.ok()) { - // Wait until the compaction completes - MutexLock l(&mutex_); - while (imm_ != NULL && bg_error_.ok()) { - bg_cv_.Wait(); - } - if (imm_ != NULL) { - s = bg_error_; - } - } - return s; -} - -void DBImpl::MaybeScheduleCompaction() { - mutex_.AssertHeld(); - if (bg_compaction_scheduled_) { - // Already scheduled - } else if (shutting_down_.Acquire_Load()) { - // DB is being deleted; no more background compactions - } else if (imm_ == NULL && - manual_compaction_ == NULL && - !versions_->NeedsCompaction()) { - // No work to be done - } else { - bg_compaction_scheduled_ = true; - env_->Schedule(&DBImpl::BGWork, this); - } -} - -void DBImpl::BGWork(void* db) { - reinterpret_cast(db)->BackgroundCall(); -} - -void DBImpl::BackgroundCall() { - MutexLock l(&mutex_); - assert(bg_compaction_scheduled_); - if (!shutting_down_.Acquire_Load()) { - Status s = BackgroundCompaction(); - if (s.ok()) { - // Success - } else if (shutting_down_.Acquire_Load()) { - // Error most likely due to shutdown; do not wait - } else { - // Wait a little bit before retrying background compaction in - // case this is an environmental problem and we do not want to - // chew up resources for failed compactions for the duration of - // the problem. - bg_cv_.SignalAll(); // In case a waiter can proceed despite the error - Log(options_.info_log, "Waiting after background compaction error: %s", - s.ToString().c_str()); - mutex_.Unlock(); - env_->SleepForMicroseconds(1000000); - mutex_.Lock(); - } - } - - bg_compaction_scheduled_ = false; - - // Previous compaction may have produced too many files in a level, - // so reschedule another compaction if needed. - MaybeScheduleCompaction(); - bg_cv_.SignalAll(); -} - -Status DBImpl::BackgroundCompaction() { - mutex_.AssertHeld(); - - if (imm_ != NULL) { - return CompactMemTable(); - } - - Compaction* c; - bool is_manual = (manual_compaction_ != NULL); - InternalKey manual_end; - if (is_manual) { - ManualCompaction* m = manual_compaction_; - c = versions_->CompactRange(m->level, m->begin, m->end); - m->done = (c == NULL); - if (c != NULL) { - manual_end = c->input(0, c->num_input_files(0) - 1)->largest; - } - Log(options_.info_log, - "Manual compaction at level-%d from %s .. %s; will stop at %s\n", - m->level, - (m->begin ? m->begin->DebugString().c_str() : "(begin)"), - (m->end ? m->end->DebugString().c_str() : "(end)"), - (m->done ? "(end)" : manual_end.DebugString().c_str())); - } else { - c = versions_->PickCompaction(); - } - - Status status; - if (c == NULL) { - // Nothing to do - } else if (!is_manual && c->IsTrivialMove()) { - // Move file to next level - assert(c->num_input_files(0) == 1); - FileMetaData* f = c->input(0, 0); - c->edit()->DeleteFile(c->level(), f->number); - c->edit()->AddFile(c->level() + 1, f->number, f->file_size, - f->smallest, f->largest); - status = versions_->LogAndApply(c->edit(), &mutex_); - VersionSet::LevelSummaryStorage tmp; - Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", - static_cast(f->number), - c->level() + 1, - static_cast(f->file_size), - status.ToString().c_str(), - versions_->LevelSummary(&tmp)); - } else { - CompactionState* compact = new CompactionState(c); - status = DoCompactionWork(compact); - CleanupCompaction(compact); - c->ReleaseInputs(); - DeleteObsoleteFiles(); - } - delete c; - - if (status.ok()) { - // Done - } else if (shutting_down_.Acquire_Load()) { - // Ignore compaction errors found during shutting down - } else { - Log(options_.info_log, - "Compaction error: %s", status.ToString().c_str()); - if (options_.paranoid_checks && bg_error_.ok()) { - bg_error_ = status; - } - } - - if (is_manual) { - ManualCompaction* m = manual_compaction_; - if (!status.ok()) { - m->done = true; - } - if (!m->done) { - // We only compacted part of the requested range. Update *m - // to the range that is left to be compacted. - m->tmp_storage = manual_end; - m->begin = &m->tmp_storage; - } - manual_compaction_ = NULL; - } - return status; -} - -void DBImpl::CleanupCompaction(CompactionState* compact) { - mutex_.AssertHeld(); - if (compact->builder != NULL) { - // May happen if we get a shutdown call in the middle of compaction - compact->builder->Abandon(); - delete compact->builder; - } else { - assert(compact->outfile == NULL); - } - delete compact->outfile; - for (size_t i = 0; i < compact->outputs.size(); i++) { - const CompactionState::Output& out = compact->outputs[i]; - pending_outputs_.erase(out.number); - } - delete compact; -} - -Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { - assert(compact != NULL); - assert(compact->builder == NULL); - uint64_t file_number; - { - mutex_.Lock(); - file_number = versions_->NewFileNumber(); - pending_outputs_.insert(file_number); - CompactionState::Output out; - out.number = file_number; - out.smallest.Clear(); - out.largest.Clear(); - compact->outputs.push_back(out); - mutex_.Unlock(); - } - - // Make the output file - std::string fname = TableFileName(dbname_, file_number); - Status s = env_->NewWritableFile(fname, &compact->outfile); - if (s.ok()) { - compact->builder = new TableBuilder(options_, compact->outfile); - } - return s; -} - -Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, - Iterator* input) { - assert(compact != NULL); - assert(compact->outfile != NULL); - assert(compact->builder != NULL); - - const uint64_t output_number = compact->current_output()->number; - assert(output_number != 0); - - // Check for iterator errors - Status s = input->status(); - const uint64_t current_entries = compact->builder->NumEntries(); - if (s.ok()) { - s = compact->builder->Finish(); - } else { - compact->builder->Abandon(); - } - const uint64_t current_bytes = compact->builder->FileSize(); - compact->current_output()->file_size = current_bytes; - compact->total_bytes += current_bytes; - delete compact->builder; - compact->builder = NULL; - - // Finish and check for file errors - if (s.ok()) { - s = compact->outfile->Sync(); - } - if (s.ok()) { - s = compact->outfile->Close(); - } - delete compact->outfile; - compact->outfile = NULL; - - if (s.ok() && current_entries > 0) { - // Verify that the table is usable - Iterator* iter = table_cache_->NewIterator(ReadOptions(), - output_number, - current_bytes); - s = iter->status(); - delete iter; - if (s.ok()) { - Log(options_.info_log, - "Generated table #%llu: %lld keys, %lld bytes", - (unsigned long long) output_number, - (unsigned long long) current_entries, - (unsigned long long) current_bytes); - } - } - return s; -} - - -Status DBImpl::InstallCompactionResults(CompactionState* compact) { - mutex_.AssertHeld(); - Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", - compact->compaction->num_input_files(0), - compact->compaction->level(), - compact->compaction->num_input_files(1), - compact->compaction->level() + 1, - static_cast(compact->total_bytes)); - - // Add compaction outputs - compact->compaction->AddInputDeletions(compact->compaction->edit()); - const int level = compact->compaction->level(); - for (size_t i = 0; i < compact->outputs.size(); i++) { - const CompactionState::Output& out = compact->outputs[i]; - compact->compaction->edit()->AddFile( - level + 1, - out.number, out.file_size, out.smallest, out.largest); - } - return versions_->LogAndApply(compact->compaction->edit(), &mutex_); -} - -Status DBImpl::DoCompactionWork(CompactionState* compact) { - const uint64_t start_micros = env_->NowMicros(); - int64_t imm_micros = 0; // Micros spent doing imm_ compactions - - Log(options_.info_log, "Compacting %d@%d + %d@%d files", - compact->compaction->num_input_files(0), - compact->compaction->level(), - compact->compaction->num_input_files(1), - compact->compaction->level() + 1); - - assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); - assert(compact->builder == NULL); - assert(compact->outfile == NULL); - if (snapshots_.empty()) { - compact->smallest_snapshot = versions_->LastSequence(); - } else { - compact->smallest_snapshot = snapshots_.oldest()->number_; - } - - // Release mutex while we're actually doing the compaction work - mutex_.Unlock(); - - Iterator* input = versions_->MakeInputIterator(compact->compaction); - input->SeekToFirst(); - Status status; - ParsedInternalKey ikey; - std::string current_user_key; - bool has_current_user_key = false; - SequenceNumber last_sequence_for_key = kMaxSequenceNumber; - for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { - // Prioritize immutable compaction work - if (has_imm_.NoBarrier_Load() != NULL) { - const uint64_t imm_start = env_->NowMicros(); - mutex_.Lock(); - if (imm_ != NULL) { - CompactMemTable(); - bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary - } - mutex_.Unlock(); - imm_micros += (env_->NowMicros() - imm_start); - } - - Slice key = input->key(); - if (compact->compaction->ShouldStopBefore(key) && - compact->builder != NULL) { - status = FinishCompactionOutputFile(compact, input); - if (!status.ok()) { - break; - } - } - - // Handle key/value, add to state, etc. - bool drop = false; - if (!ParseInternalKey(key, &ikey)) { - // Do not hide error keys - current_user_key.clear(); - has_current_user_key = false; - last_sequence_for_key = kMaxSequenceNumber; - } else { - if (!has_current_user_key || - user_comparator()->Compare(ikey.user_key, - Slice(current_user_key)) != 0) { - // First occurrence of this user key - current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); - has_current_user_key = true; - last_sequence_for_key = kMaxSequenceNumber; - } - - if (last_sequence_for_key <= compact->smallest_snapshot) { - // Hidden by an newer entry for same user key - drop = true; // (A) - } else if (ikey.type == kTypeDeletion && - ikey.sequence <= compact->smallest_snapshot && - compact->compaction->IsBaseLevelForKey(ikey.user_key)) { - // For this user key: - // (1) there is no data in higher levels - // (2) data in lower levels will have larger sequence numbers - // (3) data in layers that are being compacted here and have - // smaller sequence numbers will be dropped in the next - // few iterations of this loop (by rule (A) above). - // Therefore this deletion marker is obsolete and can be dropped. - drop = true; - } - - last_sequence_for_key = ikey.sequence; - } -#if 0 - Log(options_.info_log, - " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " - "%d smallest_snapshot: %d", - ikey.user_key.ToString().c_str(), - (int)ikey.sequence, ikey.type, kTypeValue, drop, - compact->compaction->IsBaseLevelForKey(ikey.user_key), - (int)last_sequence_for_key, (int)compact->smallest_snapshot); -#endif - - if (!drop) { - // Open output file if necessary - if (compact->builder == NULL) { - status = OpenCompactionOutputFile(compact); - if (!status.ok()) { - break; - } - } - if (compact->builder->NumEntries() == 0) { - compact->current_output()->smallest.DecodeFrom(key); - } - compact->current_output()->largest.DecodeFrom(key); - compact->builder->Add(key, input->value()); - - // Close output file if it is big enough - if (compact->builder->FileSize() >= - compact->compaction->MaxOutputFileSize()) { - status = FinishCompactionOutputFile(compact, input); - if (!status.ok()) { - break; - } - } - } - - input->Next(); - } - - if (status.ok() && shutting_down_.Acquire_Load()) { - status = Status::IOError("Deleting DB during compaction"); - } - if (status.ok() && compact->builder != NULL) { - status = FinishCompactionOutputFile(compact, input); - } - if (status.ok()) { - status = input->status(); - } - delete input; - input = NULL; - - CompactionStats stats; - stats.micros = env_->NowMicros() - start_micros - imm_micros; - for (int which = 0; which < 2; which++) { - for (int i = 0; i < compact->compaction->num_input_files(which); i++) { - stats.bytes_read += compact->compaction->input(which, i)->file_size; - } - } - for (size_t i = 0; i < compact->outputs.size(); i++) { - stats.bytes_written += compact->outputs[i].file_size; - } - - mutex_.Lock(); - stats_[compact->compaction->level() + 1].Add(stats); - - if (status.ok()) { - status = InstallCompactionResults(compact); - } - VersionSet::LevelSummaryStorage tmp; - Log(options_.info_log, - "compacted to: %s", versions_->LevelSummary(&tmp)); - return status; -} - -namespace { -struct IterState { - port::Mutex* mu; - Version* version; - MemTable* mem; - MemTable* imm; -}; - -static void CleanupIteratorState(void* arg1, void* arg2) { - IterState* state = reinterpret_cast(arg1); - state->mu->Lock(); - state->mem->Unref(); - if (state->imm != NULL) state->imm->Unref(); - state->version->Unref(); - state->mu->Unlock(); - delete state; -} -} // namespace - -Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, - SequenceNumber* latest_snapshot) { - IterState* cleanup = new IterState; - mutex_.Lock(); - *latest_snapshot = versions_->LastSequence(); - - // Collect together all needed child iterators - std::vector list; - list.push_back(mem_->NewIterator()); - mem_->Ref(); - if (imm_ != NULL) { - list.push_back(imm_->NewIterator()); - imm_->Ref(); - } - versions_->current()->AddIterators(options, &list); - Iterator* internal_iter = - NewMergingIterator(&internal_comparator_, &list[0], list.size()); - versions_->current()->Ref(); - - cleanup->mu = &mutex_; - cleanup->mem = mem_; - cleanup->imm = imm_; - cleanup->version = versions_->current(); - internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); - - mutex_.Unlock(); - return internal_iter; -} - -Iterator* DBImpl::TEST_NewInternalIterator() { - SequenceNumber ignored; - return NewInternalIterator(ReadOptions(), &ignored); -} - -int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { - MutexLock l(&mutex_); - return versions_->MaxNextLevelOverlappingBytes(); -} - -Status DBImpl::Get(const ReadOptions& options, - const Slice& key, - std::string* value) { - Status s; - MutexLock l(&mutex_); - SequenceNumber snapshot; - if (options.snapshot != NULL) { - snapshot = reinterpret_cast(options.snapshot)->number_; - } else { - snapshot = versions_->LastSequence(); - } - - MemTable* mem = mem_; - MemTable* imm = imm_; - Version* current = versions_->current(); - mem->Ref(); - if (imm != NULL) imm->Ref(); - current->Ref(); - - bool have_stat_update = false; - Version::GetStats stats; - - // Unlock while reading from files and memtables - { - mutex_.Unlock(); - // First look in the memtable, then in the immutable memtable (if any). - LookupKey lkey(key, snapshot); - if (mem->Get(lkey, value, &s)) { - // Done - } else if (imm != NULL && imm->Get(lkey, value, &s)) { - // Done - } else { - s = current->Get(options, lkey, value, &stats); - have_stat_update = true; - } - mutex_.Lock(); - } - - if (have_stat_update && current->UpdateStats(stats)) { - MaybeScheduleCompaction(); - } - mem->Unref(); - if (imm != NULL) imm->Unref(); - current->Unref(); - return s; -} - -Iterator* DBImpl::NewIterator(const ReadOptions& options) { - SequenceNumber latest_snapshot; - Iterator* internal_iter = NewInternalIterator(options, &latest_snapshot); - return NewDBIterator( - &dbname_, env_, user_comparator(), internal_iter, - (options.snapshot != NULL - ? reinterpret_cast(options.snapshot)->number_ - : latest_snapshot)); -} - -const Snapshot* DBImpl::GetSnapshot() { - MutexLock l(&mutex_); - return snapshots_.New(versions_->LastSequence()); -} - -void DBImpl::ReleaseSnapshot(const Snapshot* s) { - MutexLock l(&mutex_); - snapshots_.Delete(reinterpret_cast(s)); -} - -// Convenience methods -Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { - return DB::Put(o, key, val); -} - -Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { - return DB::Delete(options, key); -} - -Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { - Writer w(&mutex_); - w.batch = my_batch; - w.sync = options.sync; - w.done = false; - - MutexLock l(&mutex_); - writers_.push_back(&w); - while (!w.done && &w != writers_.front()) { - w.cv.Wait(); - } - if (w.done) { - return w.status; - } - - // May temporarily unlock and wait. - Status status = MakeRoomForWrite(my_batch == NULL); - uint64_t last_sequence = versions_->LastSequence(); - Writer* last_writer = &w; - if (status.ok() && my_batch != NULL) { // NULL batch is for compactions - WriteBatch* updates = BuildBatchGroup(&last_writer); - WriteBatchInternal::SetSequence(updates, last_sequence + 1); - last_sequence += WriteBatchInternal::Count(updates); - - // Add to log and apply to memtable. We can release the lock - // during this phase since &w is currently responsible for logging - // and protects against concurrent loggers and concurrent writes - // into mem_. - { - mutex_.Unlock(); - status = log_->AddRecord(WriteBatchInternal::Contents(updates)); - if (status.ok() && options.sync) { - status = logfile_->Sync(); - } - if (status.ok()) { - status = WriteBatchInternal::InsertInto(updates, mem_); - } - mutex_.Lock(); - } - if (updates == tmp_batch_) tmp_batch_->Clear(); - - versions_->SetLastSequence(last_sequence); - } - - while (true) { - Writer* ready = writers_.front(); - writers_.pop_front(); - if (ready != &w) { - ready->status = status; - ready->done = true; - ready->cv.Signal(); - } - if (ready == last_writer) break; - } - - // Notify new head of write queue - if (!writers_.empty()) { - writers_.front()->cv.Signal(); - } - - return status; -} - -// REQUIRES: Writer list must be non-empty -// REQUIRES: First writer must have a non-NULL batch -WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { - assert(!writers_.empty()); - Writer* first = writers_.front(); - WriteBatch* result = first->batch; - assert(result != NULL); - - size_t size = WriteBatchInternal::ByteSize(first->batch); - - // Allow the group to grow up to a maximum size, but if the - // original write is small, limit the growth so we do not slow - // down the small write too much. - size_t max_size = 1 << 20; - if (size <= (128<<10)) { - max_size = size + (128<<10); - } - - *last_writer = first; - std::deque::iterator iter = writers_.begin(); - ++iter; // Advance past "first" - for (; iter != writers_.end(); ++iter) { - Writer* w = *iter; - if (w->sync && !first->sync) { - // Do not include a sync write into a batch handled by a non-sync write. - break; - } - - if (w->batch != NULL) { - size += WriteBatchInternal::ByteSize(w->batch); - if (size > max_size) { - // Do not make batch too big - break; - } - - // Append to *reuslt - if (result == first->batch) { - // Switch to temporary batch instead of disturbing caller's batch - result = tmp_batch_; - assert(WriteBatchInternal::Count(result) == 0); - WriteBatchInternal::Append(result, first->batch); - } - WriteBatchInternal::Append(result, w->batch); - } - *last_writer = w; - } - return result; -} - -// REQUIRES: mutex_ is held -// REQUIRES: this thread is currently at the front of the writer queue -Status DBImpl::MakeRoomForWrite(bool force) { - mutex_.AssertHeld(); - assert(!writers_.empty()); - bool allow_delay = !force; - Status s; - while (true) { - if (!bg_error_.ok()) { - // Yield previous error - s = bg_error_; - break; - } else if ( - allow_delay && - versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) { - // We are getting close to hitting a hard limit on the number of - // L0 files. Rather than delaying a single write by several - // seconds when we hit the hard limit, start delaying each - // individual write by 1ms to reduce latency variance. Also, - // this delay hands over some CPU to the compaction thread in - // case it is sharing the same core as the writer. - mutex_.Unlock(); - env_->SleepForMicroseconds(1000); - allow_delay = false; // Do not delay a single write more than once - mutex_.Lock(); - } else if (!force && - (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { - // There is room in current memtable - break; - } else if (imm_ != NULL) { - // We have filled up the current memtable, but the previous - // one is still being compacted, so we wait. - bg_cv_.Wait(); - } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { - // There are too many level-0 files. - Log(options_.info_log, "waiting...\n"); - bg_cv_.Wait(); - } else { - // Attempt to switch to a new memtable and trigger compaction of old - assert(versions_->PrevLogNumber() == 0); - uint64_t new_log_number = versions_->NewFileNumber(); - WritableFile* lfile = NULL; - s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); - if (!s.ok()) { - // Avoid chewing through file number space in a tight loop. - versions_->ReuseFileNumber(new_log_number); - break; - } - delete log_; - delete logfile_; - logfile_ = lfile; - logfile_number_ = new_log_number; - log_ = new log::Writer(lfile); - imm_ = mem_; - has_imm_.Release_Store(imm_); - mem_ = new MemTable(internal_comparator_); - mem_->Ref(); - force = false; // Do not force another compaction if have room - MaybeScheduleCompaction(); - } - } - return s; -} - -bool DBImpl::GetProperty(const Slice& property, std::string* value) { - value->clear(); - - MutexLock l(&mutex_); - Slice in = property; - Slice prefix("leveldb."); - if (!in.starts_with(prefix)) return false; - in.remove_prefix(prefix.size()); - - if (in.starts_with("num-files-at-level")) { - in.remove_prefix(strlen("num-files-at-level")); - uint64_t level; - bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); - if (!ok || level >= config::kNumLevels) { - return false; - } else { - char buf[100]; - snprintf(buf, sizeof(buf), "%d", - versions_->NumLevelFiles(static_cast(level))); - *value = buf; - return true; - } - } else if (in == "stats") { - char buf[200]; - snprintf(buf, sizeof(buf), - " Compactions\n" - "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" - "--------------------------------------------------\n" - ); - value->append(buf); - for (int level = 0; level < config::kNumLevels; level++) { - int files = versions_->NumLevelFiles(level); - if (stats_[level].micros > 0 || files > 0) { - snprintf( - buf, sizeof(buf), - "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", - level, - files, - versions_->NumLevelBytes(level) / 1048576.0, - stats_[level].micros / 1e6, - stats_[level].bytes_read / 1048576.0, - stats_[level].bytes_written / 1048576.0); - value->append(buf); - } - } - return true; - } else if (in == "sstables") { - *value = versions_->current()->DebugString(); - return true; - } - - return false; -} - -void DBImpl::GetApproximateSizes( - const Range* range, int n, - uint64_t* sizes) { - // TODO(opt): better implementation - Version* v; - { - MutexLock l(&mutex_); - versions_->current()->Ref(); - v = versions_->current(); - } - - for (int i = 0; i < n; i++) { - // Convert user_key into a corresponding internal key. - InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); - InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); - uint64_t start = versions_->ApproximateOffsetOf(v, k1); - uint64_t limit = versions_->ApproximateOffsetOf(v, k2); - sizes[i] = (limit >= start ? limit - start : 0); - } - - { - MutexLock l(&mutex_); - v->Unref(); - } -} - -// Default implementations of convenience methods that subclasses of DB -// can call if they wish -Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { - WriteBatch batch; - batch.Put(key, value); - return Write(opt, &batch); -} - -Status DB::Delete(const WriteOptions& opt, const Slice& key) { - WriteBatch batch; - batch.Delete(key); - return Write(opt, &batch); -} - -DB::~DB() { } - -Status DB::Open(const Options& options, const std::string& dbname, - DB** dbptr) { - *dbptr = NULL; - - DBImpl* impl = new DBImpl(options, dbname); - impl->mutex_.Lock(); - VersionEdit edit; - Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists - if (s.ok()) { - uint64_t new_log_number = impl->versions_->NewFileNumber(); - WritableFile* lfile; - s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), - &lfile); - if (s.ok()) { - edit.SetLogNumber(new_log_number); - impl->logfile_ = lfile; - impl->logfile_number_ = new_log_number; - impl->log_ = new log::Writer(lfile); - s = impl->versions_->LogAndApply(&edit, &impl->mutex_); - } - if (s.ok()) { - impl->DeleteObsoleteFiles(); - impl->MaybeScheduleCompaction(); - } - } - impl->mutex_.Unlock(); - if (s.ok()) { - *dbptr = impl; - } else { - delete impl; - } - return s; -} - -Snapshot::~Snapshot() { -} - -Status DestroyDB(const std::string& dbname, const Options& options) { - Env* env = options.env; - std::vector filenames; - // Ignore error in case directory does not exist - env->GetChildren(dbname, &filenames); - if (filenames.empty()) { - return Status::OK(); - } - - FileLock* lock; - const std::string lockname = LockFileName(dbname); - Status result = env->LockFile(lockname, &lock); - if (result.ok()) { - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) && - type != kDBLockFile) { // Lock file will be deleted at end - Status del = env->DeleteFile(dbname + "/" + filenames[i]); - if (result.ok() && !del.ok()) { - result = del; - } - } - } - env->UnlockFile(lock); // Ignore error since state is already gone - env->DeleteFile(lockname); - env->DeleteDir(dbname); // Ignore error in case dir contains other files - } - return result; -} - -} // namespace leveldb diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h deleted file mode 100644 index bd29dd805..000000000 --- a/src/leveldb/db/db_impl.h +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_ -#define STORAGE_LEVELDB_DB_DB_IMPL_H_ - -#include -#include -#include "db/dbformat.h" -#include "db/log_writer.h" -#include "db/snapshot.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "port/port.h" -#include "port/thread_annotations.h" - -namespace leveldb { - -class MemTable; -class TableCache; -class Version; -class VersionEdit; -class VersionSet; - -class DBImpl : public DB { - public: - DBImpl(const Options& options, const std::string& dbname); - virtual ~DBImpl(); - - // Implementations of the DB interface - virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); - virtual Status Delete(const WriteOptions&, const Slice& key); - virtual Status Write(const WriteOptions& options, WriteBatch* updates); - virtual Status Get(const ReadOptions& options, - const Slice& key, - std::string* value); - virtual Iterator* NewIterator(const ReadOptions&); - virtual const Snapshot* GetSnapshot(); - virtual void ReleaseSnapshot(const Snapshot* snapshot); - virtual bool GetProperty(const Slice& property, std::string* value); - virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); - virtual void CompactRange(const Slice* begin, const Slice* end); - - // Extra methods (for testing) that are not in the public DB interface - - // Compact any files in the named level that overlap [*begin,*end] - void TEST_CompactRange(int level, const Slice* begin, const Slice* end); - - // Force current memtable contents to be compacted. - Status TEST_CompactMemTable(); - - // Return an internal iterator over the current state of the database. - // The keys of this iterator are internal keys (see format.h). - // The returned iterator should be deleted when no longer needed. - Iterator* TEST_NewInternalIterator(); - - // Return the maximum overlapping data (in bytes) at next level for any - // file at a level >= 1. - int64_t TEST_MaxNextLevelOverlappingBytes(); - - private: - friend class DB; - struct CompactionState; - struct Writer; - - Iterator* NewInternalIterator(const ReadOptions&, - SequenceNumber* latest_snapshot); - - Status NewDB(); - - // Recover the descriptor from persistent storage. May do a significant - // amount of work to recover recently logged updates. Any changes to - // be made to the descriptor are added to *edit. - Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - void MaybeIgnoreError(Status* s) const; - - // Delete any unneeded files and stale in-memory entries. - void DeleteObsoleteFiles(); - - // Compact the in-memory write buffer to disk. Switches to a new - // log-file/memtable and writes a new descriptor iff successful. - Status CompactMemTable() - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status RecoverLogFile(uint64_t log_number, - VersionEdit* edit, - SequenceNumber* max_sequence) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status MakeRoomForWrite(bool force /* compact even if there is room? */) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - WriteBatch* BuildBatchGroup(Writer** last_writer); - - void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); - static void BGWork(void* db); - void BackgroundCall(); - Status BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void CleanupCompaction(CompactionState* compact) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - Status DoCompactionWork(CompactionState* compact) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status OpenCompactionOutputFile(CompactionState* compact); - Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); - Status InstallCompactionResults(CompactionState* compact) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Constant after construction - Env* const env_; - const InternalKeyComparator internal_comparator_; - const InternalFilterPolicy internal_filter_policy_; - const Options options_; // options_.comparator == &internal_comparator_ - bool owns_info_log_; - bool owns_cache_; - const std::string dbname_; - - // table_cache_ provides its own synchronization - TableCache* table_cache_; - - // Lock over the persistent DB state. Non-NULL iff successfully acquired. - FileLock* db_lock_; - - // State below is protected by mutex_ - port::Mutex mutex_; - port::AtomicPointer shutting_down_; - port::CondVar bg_cv_; // Signalled when background work finishes - MemTable* mem_; - MemTable* imm_; // Memtable being compacted - port::AtomicPointer has_imm_; // So bg thread can detect non-NULL imm_ - WritableFile* logfile_; - uint64_t logfile_number_; - log::Writer* log_; - - // Queue of writers. - std::deque writers_; - WriteBatch* tmp_batch_; - - SnapshotList snapshots_; - - // Set of table files to protect from deletion because they are - // part of ongoing compactions. - std::set pending_outputs_; - - // Has a background compaction been scheduled or is running? - bool bg_compaction_scheduled_; - - // Information for a manual compaction - struct ManualCompaction { - int level; - bool done; - const InternalKey* begin; // NULL means beginning of key range - const InternalKey* end; // NULL means end of key range - InternalKey tmp_storage; // Used to keep track of compaction progress - }; - ManualCompaction* manual_compaction_; - - VersionSet* versions_; - - // Have we encountered a background error in paranoid mode? - Status bg_error_; - - // Per level compaction stats. stats_[level] stores the stats for - // compactions that produced data for the specified "level". - struct CompactionStats { - int64_t micros; - int64_t bytes_read; - int64_t bytes_written; - - CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { } - - void Add(const CompactionStats& c) { - this->micros += c.micros; - this->bytes_read += c.bytes_read; - this->bytes_written += c.bytes_written; - } - }; - CompactionStats stats_[config::kNumLevels]; - - // No copying allowed - DBImpl(const DBImpl&); - void operator=(const DBImpl&); - - const Comparator* user_comparator() const { - return internal_comparator_.user_comparator(); - } -}; - -// Sanitize db options. The caller should delete result.info_log if -// it is not equal to src.info_log. -extern Options SanitizeOptions(const std::string& db, - const InternalKeyComparator* icmp, - const InternalFilterPolicy* ipolicy, - const Options& src); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/src/leveldb/db/db_iter.cc b/src/leveldb/db/db_iter.cc deleted file mode 100644 index 87dca2ded..000000000 --- a/src/leveldb/db/db_iter.cc +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/db_iter.h" - -#include "db/filename.h" -#include "db/dbformat.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "port/port.h" -#include "util/logging.h" -#include "util/mutexlock.h" - -namespace leveldb { - -#if 0 -static void DumpInternalIter(Iterator* iter) { - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - ParsedInternalKey k; - if (!ParseInternalKey(iter->key(), &k)) { - fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); - } else { - fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); - } - } -} -#endif - -namespace { - -// Memtables and sstables that make the DB representation contain -// (userkey,seq,type) => uservalue entries. DBIter -// combines multiple entries for the same userkey found in the DB -// representation into a single entry while accounting for sequence -// numbers, deletion markers, overwrites, etc. -class DBIter: public Iterator { - public: - // Which direction is the iterator currently moving? - // (1) When moving forward, the internal iterator is positioned at - // the exact entry that yields this->key(), this->value() - // (2) When moving backwards, the internal iterator is positioned - // just before all entries whose user key == this->key(). - enum Direction { - kForward, - kReverse - }; - - DBIter(const std::string* dbname, Env* env, - const Comparator* cmp, Iterator* iter, SequenceNumber s) - : dbname_(dbname), - env_(env), - user_comparator_(cmp), - iter_(iter), - sequence_(s), - direction_(kForward), - valid_(false) { - } - virtual ~DBIter() { - delete iter_; - } - virtual bool Valid() const { return valid_; } - virtual Slice key() const { - assert(valid_); - return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; - } - virtual Slice value() const { - assert(valid_); - return (direction_ == kForward) ? iter_->value() : saved_value_; - } - virtual Status status() const { - if (status_.ok()) { - return iter_->status(); - } else { - return status_; - } - } - - virtual void Next(); - virtual void Prev(); - virtual void Seek(const Slice& target); - virtual void SeekToFirst(); - virtual void SeekToLast(); - - private: - void FindNextUserEntry(bool skipping, std::string* skip); - void FindPrevUserEntry(); - bool ParseKey(ParsedInternalKey* key); - - inline void SaveKey(const Slice& k, std::string* dst) { - dst->assign(k.data(), k.size()); - } - - inline void ClearSavedValue() { - if (saved_value_.capacity() > 1048576) { - std::string empty; - swap(empty, saved_value_); - } else { - saved_value_.clear(); - } - } - - const std::string* const dbname_; - Env* const env_; - const Comparator* const user_comparator_; - Iterator* const iter_; - SequenceNumber const sequence_; - - Status status_; - std::string saved_key_; // == current key when direction_==kReverse - std::string saved_value_; // == current raw value when direction_==kReverse - Direction direction_; - bool valid_; - - // No copying allowed - DBIter(const DBIter&); - void operator=(const DBIter&); -}; - -inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { - if (!ParseInternalKey(iter_->key(), ikey)) { - status_ = Status::Corruption("corrupted internal key in DBIter"); - return false; - } else { - return true; - } -} - -void DBIter::Next() { - assert(valid_); - - if (direction_ == kReverse) { // Switch directions? - direction_ = kForward; - // iter_ is pointing just before the entries for this->key(), - // so advance into the range of entries for this->key() and then - // use the normal skipping code below. - if (!iter_->Valid()) { - iter_->SeekToFirst(); - } else { - iter_->Next(); - } - if (!iter_->Valid()) { - valid_ = false; - saved_key_.clear(); - return; - } - } - - // Temporarily use saved_key_ as storage for key to skip. - std::string* skip = &saved_key_; - SaveKey(ExtractUserKey(iter_->key()), skip); - FindNextUserEntry(true, skip); -} - -void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { - // Loop until we hit an acceptable entry to yield - assert(iter_->Valid()); - assert(direction_ == kForward); - do { - ParsedInternalKey ikey; - if (ParseKey(&ikey) && ikey.sequence <= sequence_) { - switch (ikey.type) { - case kTypeDeletion: - // Arrange to skip all upcoming entries for this key since - // they are hidden by this deletion. - SaveKey(ikey.user_key, skip); - skipping = true; - break; - case kTypeValue: - if (skipping && - user_comparator_->Compare(ikey.user_key, *skip) <= 0) { - // Entry hidden - } else { - valid_ = true; - saved_key_.clear(); - return; - } - break; - } - } - iter_->Next(); - } while (iter_->Valid()); - saved_key_.clear(); - valid_ = false; -} - -void DBIter::Prev() { - assert(valid_); - - if (direction_ == kForward) { // Switch directions? - // iter_ is pointing at the current entry. Scan backwards until - // the key changes so we can use the normal reverse scanning code. - assert(iter_->Valid()); // Otherwise valid_ would have been false - SaveKey(ExtractUserKey(iter_->key()), &saved_key_); - while (true) { - iter_->Prev(); - if (!iter_->Valid()) { - valid_ = false; - saved_key_.clear(); - ClearSavedValue(); - return; - } - if (user_comparator_->Compare(ExtractUserKey(iter_->key()), - saved_key_) < 0) { - break; - } - } - direction_ = kReverse; - } - - FindPrevUserEntry(); -} - -void DBIter::FindPrevUserEntry() { - assert(direction_ == kReverse); - - ValueType value_type = kTypeDeletion; - if (iter_->Valid()) { - do { - ParsedInternalKey ikey; - if (ParseKey(&ikey) && ikey.sequence <= sequence_) { - if ((value_type != kTypeDeletion) && - user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { - // We encountered a non-deleted value in entries for previous keys, - break; - } - value_type = ikey.type; - if (value_type == kTypeDeletion) { - saved_key_.clear(); - ClearSavedValue(); - } else { - Slice raw_value = iter_->value(); - if (saved_value_.capacity() > raw_value.size() + 1048576) { - std::string empty; - swap(empty, saved_value_); - } - SaveKey(ExtractUserKey(iter_->key()), &saved_key_); - saved_value_.assign(raw_value.data(), raw_value.size()); - } - } - iter_->Prev(); - } while (iter_->Valid()); - } - - if (value_type == kTypeDeletion) { - // End - valid_ = false; - saved_key_.clear(); - ClearSavedValue(); - direction_ = kForward; - } else { - valid_ = true; - } -} - -void DBIter::Seek(const Slice& target) { - direction_ = kForward; - ClearSavedValue(); - saved_key_.clear(); - AppendInternalKey( - &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek)); - iter_->Seek(saved_key_); - if (iter_->Valid()) { - FindNextUserEntry(false, &saved_key_ /* temporary storage */); - } else { - valid_ = false; - } -} - -void DBIter::SeekToFirst() { - direction_ = kForward; - ClearSavedValue(); - iter_->SeekToFirst(); - if (iter_->Valid()) { - FindNextUserEntry(false, &saved_key_ /* temporary storage */); - } else { - valid_ = false; - } -} - -void DBIter::SeekToLast() { - direction_ = kReverse; - ClearSavedValue(); - iter_->SeekToLast(); - FindPrevUserEntry(); -} - -} // anonymous namespace - -Iterator* NewDBIterator( - const std::string* dbname, - Env* env, - const Comparator* user_key_comparator, - Iterator* internal_iter, - const SequenceNumber& sequence) { - return new DBIter(dbname, env, user_key_comparator, internal_iter, sequence); -} - -} // namespace leveldb diff --git a/src/leveldb/db/db_iter.h b/src/leveldb/db/db_iter.h deleted file mode 100644 index d9e1b174a..000000000 --- a/src/leveldb/db/db_iter.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_ -#define STORAGE_LEVELDB_DB_DB_ITER_H_ - -#include -#include "leveldb/db.h" -#include "db/dbformat.h" - -namespace leveldb { - -// Return a new iterator that converts internal keys (yielded by -// "*internal_iter") that were live at the specified "sequence" number -// into appropriate user keys. -extern Iterator* NewDBIterator( - const std::string* dbname, - Env* env, - const Comparator* user_key_comparator, - Iterator* internal_iter, - const SequenceNumber& sequence); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc deleted file mode 100644 index 684ea3bdb..000000000 --- a/src/leveldb/db/db_test.cc +++ /dev/null @@ -1,2027 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" -#include "leveldb/filter_policy.h" -#include "db/db_impl.h" -#include "db/filename.h" -#include "db/version_set.h" -#include "db/write_batch_internal.h" -#include "leveldb/cache.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "util/hash.h" -#include "util/logging.h" -#include "util/mutexlock.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static std::string RandomString(Random* rnd, int len) { - std::string r; - test::RandomString(rnd, len, &r); - return r; -} - -namespace { -class AtomicCounter { - private: - port::Mutex mu_; - int count_; - public: - AtomicCounter() : count_(0) { } - void Increment() { - MutexLock l(&mu_); - count_++; - } - int Read() { - MutexLock l(&mu_); - return count_; - } - void Reset() { - MutexLock l(&mu_); - count_ = 0; - } -}; -} - -// Special Env used to delay background operations -class SpecialEnv : public EnvWrapper { - public: - // sstable Sync() calls are blocked while this pointer is non-NULL. - port::AtomicPointer delay_sstable_sync_; - - // Simulate no-space errors while this pointer is non-NULL. - port::AtomicPointer no_space_; - - // Simulate non-writable file system while this pointer is non-NULL - port::AtomicPointer non_writable_; - - // Force sync of manifest files to fail while this pointer is non-NULL - port::AtomicPointer manifest_sync_error_; - - // Force write to manifest files to fail while this pointer is non-NULL - port::AtomicPointer manifest_write_error_; - - bool count_random_reads_; - AtomicCounter random_read_counter_; - - AtomicCounter sleep_counter_; - - explicit SpecialEnv(Env* base) : EnvWrapper(base) { - delay_sstable_sync_.Release_Store(NULL); - no_space_.Release_Store(NULL); - non_writable_.Release_Store(NULL); - count_random_reads_ = false; - manifest_sync_error_.Release_Store(NULL); - manifest_write_error_.Release_Store(NULL); - } - - Status NewWritableFile(const std::string& f, WritableFile** r) { - class SSTableFile : public WritableFile { - private: - SpecialEnv* env_; - WritableFile* base_; - - public: - SSTableFile(SpecialEnv* env, WritableFile* base) - : env_(env), - base_(base) { - } - ~SSTableFile() { delete base_; } - Status Append(const Slice& data) { - if (env_->no_space_.Acquire_Load() != NULL) { - // Drop writes on the floor - return Status::OK(); - } else { - return base_->Append(data); - } - } - Status Close() { return base_->Close(); } - Status Flush() { return base_->Flush(); } - Status Sync() { - while (env_->delay_sstable_sync_.Acquire_Load() != NULL) { - env_->SleepForMicroseconds(100000); - } - return base_->Sync(); - } - }; - class ManifestFile : public WritableFile { - private: - SpecialEnv* env_; - WritableFile* base_; - public: - ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { } - ~ManifestFile() { delete base_; } - Status Append(const Slice& data) { - if (env_->manifest_write_error_.Acquire_Load() != NULL) { - return Status::IOError("simulated writer error"); - } else { - return base_->Append(data); - } - } - Status Close() { return base_->Close(); } - Status Flush() { return base_->Flush(); } - Status Sync() { - if (env_->manifest_sync_error_.Acquire_Load() != NULL) { - return Status::IOError("simulated sync error"); - } else { - return base_->Sync(); - } - } - }; - - if (non_writable_.Acquire_Load() != NULL) { - return Status::IOError("simulated write error"); - } - - Status s = target()->NewWritableFile(f, r); - if (s.ok()) { - if (strstr(f.c_str(), ".sst") != NULL) { - *r = new SSTableFile(this, *r); - } else if (strstr(f.c_str(), "MANIFEST") != NULL) { - *r = new ManifestFile(this, *r); - } - } - return s; - } - - Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { - class CountingFile : public RandomAccessFile { - private: - RandomAccessFile* target_; - AtomicCounter* counter_; - public: - CountingFile(RandomAccessFile* target, AtomicCounter* counter) - : target_(target), counter_(counter) { - } - virtual ~CountingFile() { delete target_; } - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - counter_->Increment(); - return target_->Read(offset, n, result, scratch); - } - }; - - Status s = target()->NewRandomAccessFile(f, r); - if (s.ok() && count_random_reads_) { - *r = new CountingFile(*r, &random_read_counter_); - } - return s; - } - - virtual void SleepForMicroseconds(int micros) { - sleep_counter_.Increment(); - target()->SleepForMicroseconds(micros); - } -}; - -class DBTest { - private: - const FilterPolicy* filter_policy_; - - // Sequence of option configurations to try - enum OptionConfig { - kDefault, - kFilter, - kUncompressed, - kEnd - }; - int option_config_; - - public: - std::string dbname_; - SpecialEnv* env_; - DB* db_; - - Options last_options_; - - DBTest() : option_config_(kDefault), - env_(new SpecialEnv(Env::Default())) { - filter_policy_ = NewBloomFilterPolicy(10); - dbname_ = test::TmpDir() + "/db_test"; - DestroyDB(dbname_, Options()); - db_ = NULL; - Reopen(); - } - - ~DBTest() { - delete db_; - DestroyDB(dbname_, Options()); - delete env_; - delete filter_policy_; - } - - // Switch to a fresh database with the next option configuration to - // test. Return false if there are no more configurations to test. - bool ChangeOptions() { - option_config_++; - if (option_config_ >= kEnd) { - return false; - } else { - DestroyAndReopen(); - return true; - } - } - - // Return the current option configuration. - Options CurrentOptions() { - Options options; - switch (option_config_) { - case kFilter: - options.filter_policy = filter_policy_; - break; - case kUncompressed: - options.compression = kNoCompression; - break; - default: - break; - } - return options; - } - - DBImpl* dbfull() { - return reinterpret_cast(db_); - } - - void Reopen(Options* options = NULL) { - ASSERT_OK(TryReopen(options)); - } - - void Close() { - delete db_; - db_ = NULL; - } - - void DestroyAndReopen(Options* options = NULL) { - delete db_; - db_ = NULL; - DestroyDB(dbname_, Options()); - ASSERT_OK(TryReopen(options)); - } - - Status TryReopen(Options* options) { - delete db_; - db_ = NULL; - Options opts; - if (options != NULL) { - opts = *options; - } else { - opts = CurrentOptions(); - opts.create_if_missing = true; - } - last_options_ = opts; - - return DB::Open(opts, dbname_, &db_); - } - - Status Put(const std::string& k, const std::string& v) { - return db_->Put(WriteOptions(), k, v); - } - - Status Delete(const std::string& k) { - return db_->Delete(WriteOptions(), k); - } - - std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { - ReadOptions options; - options.snapshot = snapshot; - std::string result; - Status s = db_->Get(options, k, &result); - if (s.IsNotFound()) { - result = "NOT_FOUND"; - } else if (!s.ok()) { - result = s.ToString(); - } - return result; - } - - // Return a string that contains all key,value pairs in order, - // formatted like "(k1->v1)(k2->v2)". - std::string Contents() { - std::vector forward; - std::string result; - Iterator* iter = db_->NewIterator(ReadOptions()); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - std::string s = IterStatus(iter); - result.push_back('('); - result.append(s); - result.push_back(')'); - forward.push_back(s); - } - - // Check reverse iteration results are the reverse of forward results - int matched = 0; - for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { - ASSERT_LT(matched, forward.size()); - ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]); - matched++; - } - ASSERT_EQ(matched, forward.size()); - - delete iter; - return result; - } - - std::string AllEntriesFor(const Slice& user_key) { - Iterator* iter = dbfull()->TEST_NewInternalIterator(); - InternalKey target(user_key, kMaxSequenceNumber, kTypeValue); - iter->Seek(target.Encode()); - std::string result; - if (!iter->status().ok()) { - result = iter->status().ToString(); - } else { - result = "[ "; - bool first = true; - while (iter->Valid()) { - ParsedInternalKey ikey; - if (!ParseInternalKey(iter->key(), &ikey)) { - result += "CORRUPTED"; - } else { - if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) { - break; - } - if (!first) { - result += ", "; - } - first = false; - switch (ikey.type) { - case kTypeValue: - result += iter->value().ToString(); - break; - case kTypeDeletion: - result += "DEL"; - break; - } - } - iter->Next(); - } - if (!first) { - result += " "; - } - result += "]"; - } - delete iter; - return result; - } - - int NumTableFilesAtLevel(int level) { - std::string property; - ASSERT_TRUE( - db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level), - &property)); - return atoi(property.c_str()); - } - - int TotalTableFiles() { - int result = 0; - for (int level = 0; level < config::kNumLevels; level++) { - result += NumTableFilesAtLevel(level); - } - return result; - } - - // Return spread of files per level - std::string FilesPerLevel() { - std::string result; - int last_non_zero_offset = 0; - for (int level = 0; level < config::kNumLevels; level++) { - int f = NumTableFilesAtLevel(level); - char buf[100]; - snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f); - result += buf; - if (f > 0) { - last_non_zero_offset = result.size(); - } - } - result.resize(last_non_zero_offset); - return result; - } - - int CountFiles() { - std::vector files; - env_->GetChildren(dbname_, &files); - return static_cast(files.size()); - } - - uint64_t Size(const Slice& start, const Slice& limit) { - Range r(start, limit); - uint64_t size; - db_->GetApproximateSizes(&r, 1, &size); - return size; - } - - void Compact(const Slice& start, const Slice& limit) { - db_->CompactRange(&start, &limit); - } - - // Do n memtable compactions, each of which produces an sstable - // covering the range [small,large]. - void MakeTables(int n, const std::string& small, const std::string& large) { - for (int i = 0; i < n; i++) { - Put(small, "begin"); - Put(large, "end"); - dbfull()->TEST_CompactMemTable(); - } - } - - // Prevent pushing of new sstables into deeper levels by adding - // tables that cover a specified range to all levels. - void FillLevels(const std::string& smallest, const std::string& largest) { - MakeTables(config::kNumLevels, smallest, largest); - } - - void DumpFileCounts(const char* label) { - fprintf(stderr, "---\n%s:\n", label); - fprintf(stderr, "maxoverlap: %lld\n", - static_cast( - dbfull()->TEST_MaxNextLevelOverlappingBytes())); - for (int level = 0; level < config::kNumLevels; level++) { - int num = NumTableFilesAtLevel(level); - if (num > 0) { - fprintf(stderr, " level %3d : %d files\n", level, num); - } - } - } - - std::string DumpSSTableList() { - std::string property; - db_->GetProperty("leveldb.sstables", &property); - return property; - } - - std::string IterStatus(Iterator* iter) { - std::string result; - if (iter->Valid()) { - result = iter->key().ToString() + "->" + iter->value().ToString(); - } else { - result = "(invalid)"; - } - return result; - } -}; - -TEST(DBTest, Empty) { - do { - ASSERT_TRUE(db_ != NULL); - ASSERT_EQ("NOT_FOUND", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, ReadWrite) { - do { - ASSERT_OK(Put("foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - ASSERT_OK(Put("bar", "v2")); - ASSERT_OK(Put("foo", "v3")); - ASSERT_EQ("v3", Get("foo")); - ASSERT_EQ("v2", Get("bar")); - } while (ChangeOptions()); -} - -TEST(DBTest, PutDeleteGet) { - do { - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); - ASSERT_EQ("v2", Get("foo")); - ASSERT_OK(db_->Delete(WriteOptions(), "foo")); - ASSERT_EQ("NOT_FOUND", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetFromImmutableLayer) { - do { - Options options = CurrentOptions(); - options.env = env_; - options.write_buffer_size = 100000; // Small write buffer - Reopen(&options); - - ASSERT_OK(Put("foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - - env_->delay_sstable_sync_.Release_Store(env_); // Block sync calls - Put("k1", std::string(100000, 'x')); // Fill memtable - Put("k2", std::string(100000, 'y')); // Trigger compaction - ASSERT_EQ("v1", Get("foo")); - env_->delay_sstable_sync_.Release_Store(NULL); // Release sync calls - } while (ChangeOptions()); -} - -TEST(DBTest, GetFromVersions) { - do { - ASSERT_OK(Put("foo", "v1")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v1", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetSnapshot) { - do { - // Try with both a short key and a long key - for (int i = 0; i < 2; i++) { - std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x'); - ASSERT_OK(Put(key, "v1")); - const Snapshot* s1 = db_->GetSnapshot(); - ASSERT_OK(Put(key, "v2")); - ASSERT_EQ("v2", Get(key)); - ASSERT_EQ("v1", Get(key, s1)); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v2", Get(key)); - ASSERT_EQ("v1", Get(key, s1)); - db_->ReleaseSnapshot(s1); - } - } while (ChangeOptions()); -} - -TEST(DBTest, GetLevel0Ordering) { - do { - // Check that we process level-0 files in correct order. The code - // below generates two level-0 files where the earlier one comes - // before the later one in the level-0 file list since the earlier - // one has a smaller "smallest" key. - ASSERT_OK(Put("bar", "b")); - ASSERT_OK(Put("foo", "v1")); - dbfull()->TEST_CompactMemTable(); - ASSERT_OK(Put("foo", "v2")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v2", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetOrderedByLevels) { - do { - ASSERT_OK(Put("foo", "v1")); - Compact("a", "z"); - ASSERT_EQ("v1", Get("foo")); - ASSERT_OK(Put("foo", "v2")); - ASSERT_EQ("v2", Get("foo")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v2", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetPicksCorrectFile) { - do { - // Arrange to have multiple files in a non-level-0 level. - ASSERT_OK(Put("a", "va")); - Compact("a", "b"); - ASSERT_OK(Put("x", "vx")); - Compact("x", "y"); - ASSERT_OK(Put("f", "vf")); - Compact("f", "g"); - ASSERT_EQ("va", Get("a")); - ASSERT_EQ("vf", Get("f")); - ASSERT_EQ("vx", Get("x")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetEncountersEmptyLevel) { - do { - // Arrange for the following to happen: - // * sstable A in level 0 - // * nothing in level 1 - // * sstable B in level 2 - // Then do enough Get() calls to arrange for an automatic compaction - // of sstable A. A bug would cause the compaction to be marked as - // occuring at level 1 (instead of the correct level 0). - - // Step 1: First place sstables in levels 0 and 2 - int compaction_count = 0; - while (NumTableFilesAtLevel(0) == 0 || - NumTableFilesAtLevel(2) == 0) { - ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2"; - compaction_count++; - Put("a", "begin"); - Put("z", "end"); - dbfull()->TEST_CompactMemTable(); - } - - // Step 2: clear level 1 if necessary. - dbfull()->TEST_CompactRange(1, NULL, NULL); - ASSERT_EQ(NumTableFilesAtLevel(0), 1); - ASSERT_EQ(NumTableFilesAtLevel(1), 0); - ASSERT_EQ(NumTableFilesAtLevel(2), 1); - - // Step 3: read a bunch of times - for (int i = 0; i < 1000; i++) { - ASSERT_EQ("NOT_FOUND", Get("missing")); - } - - // Step 4: Wait for compaction to finish - env_->SleepForMicroseconds(1000000); - - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - } while (ChangeOptions()); -} - -TEST(DBTest, IterEmpty) { - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek("foo"); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterSingle) { - ASSERT_OK(Put("a", "va")); - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek(""); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek("a"); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek("b"); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterMulti) { - ASSERT_OK(Put("a", "va")); - ASSERT_OK(Put("b", "vb")); - ASSERT_OK(Put("c", "vc")); - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek(""); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Seek("a"); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Seek("ax"); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Seek("b"); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Seek("z"); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - // Switch from reverse to forward - iter->SeekToLast(); - iter->Prev(); - iter->Prev(); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - - // Switch from forward to reverse - iter->SeekToFirst(); - iter->Next(); - iter->Next(); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - - // Make sure iter stays at snapshot - ASSERT_OK(Put("a", "va2")); - ASSERT_OK(Put("a2", "va3")); - ASSERT_OK(Put("b", "vb2")); - ASSERT_OK(Put("c", "vc2")); - ASSERT_OK(Delete("b")); - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterSmallAndLargeMix) { - ASSERT_OK(Put("a", "va")); - ASSERT_OK(Put("b", std::string(100000, 'b'))); - ASSERT_OK(Put("c", "vc")); - ASSERT_OK(Put("d", std::string(100000, 'd'))); - ASSERT_OK(Put("e", std::string(100000, 'e'))); - - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterMultiWithDelete) { - do { - ASSERT_OK(Put("a", "va")); - ASSERT_OK(Put("b", "vb")); - ASSERT_OK(Put("c", "vc")); - ASSERT_OK(Delete("b")); - ASSERT_EQ("NOT_FOUND", Get("b")); - - Iterator* iter = db_->NewIterator(ReadOptions()); - iter->Seek("c"); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - delete iter; - } while (ChangeOptions()); -} - -TEST(DBTest, Recover) { - do { - ASSERT_OK(Put("foo", "v1")); - ASSERT_OK(Put("baz", "v5")); - - Reopen(); - ASSERT_EQ("v1", Get("foo")); - - ASSERT_EQ("v1", Get("foo")); - ASSERT_EQ("v5", Get("baz")); - ASSERT_OK(Put("bar", "v2")); - ASSERT_OK(Put("foo", "v3")); - - Reopen(); - ASSERT_EQ("v3", Get("foo")); - ASSERT_OK(Put("foo", "v4")); - ASSERT_EQ("v4", Get("foo")); - ASSERT_EQ("v2", Get("bar")); - ASSERT_EQ("v5", Get("baz")); - } while (ChangeOptions()); -} - -TEST(DBTest, RecoveryWithEmptyLog) { - do { - ASSERT_OK(Put("foo", "v1")); - ASSERT_OK(Put("foo", "v2")); - Reopen(); - Reopen(); - ASSERT_OK(Put("foo", "v3")); - Reopen(); - ASSERT_EQ("v3", Get("foo")); - } while (ChangeOptions()); -} - -// Check that writes done during a memtable compaction are recovered -// if the database is shutdown during the memtable compaction. -TEST(DBTest, RecoverDuringMemtableCompaction) { - do { - Options options = CurrentOptions(); - options.env = env_; - options.write_buffer_size = 1000000; - Reopen(&options); - - // Trigger a long memtable compaction and reopen the database during it - ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file - ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable - ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction - ASSERT_OK(Put("bar", "v2")); // Goes to new log file - - Reopen(&options); - ASSERT_EQ("v1", Get("foo")); - ASSERT_EQ("v2", Get("bar")); - ASSERT_EQ(std::string(10000000, 'x'), Get("big1")); - ASSERT_EQ(std::string(1000, 'y'), Get("big2")); - } while (ChangeOptions()); -} - -static std::string Key(int i) { - char buf[100]; - snprintf(buf, sizeof(buf), "key%06d", i); - return std::string(buf); -} - -TEST(DBTest, MinorCompactionsHappen) { - Options options = CurrentOptions(); - options.write_buffer_size = 10000; - Reopen(&options); - - const int N = 500; - - int starting_num_tables = TotalTableFiles(); - for (int i = 0; i < N; i++) { - ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v'))); - } - int ending_num_tables = TotalTableFiles(); - ASSERT_GT(ending_num_tables, starting_num_tables); - - for (int i = 0; i < N; i++) { - ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); - } - - Reopen(); - - for (int i = 0; i < N; i++) { - ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); - } -} - -TEST(DBTest, RecoverWithLargeLog) { - { - Options options = CurrentOptions(); - Reopen(&options); - ASSERT_OK(Put("big1", std::string(200000, '1'))); - ASSERT_OK(Put("big2", std::string(200000, '2'))); - ASSERT_OK(Put("small3", std::string(10, '3'))); - ASSERT_OK(Put("small4", std::string(10, '4'))); - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - } - - // Make sure that if we re-open with a small write buffer size that - // we flush table files in the middle of a large log file. - Options options = CurrentOptions(); - options.write_buffer_size = 100000; - Reopen(&options); - ASSERT_EQ(NumTableFilesAtLevel(0), 3); - ASSERT_EQ(std::string(200000, '1'), Get("big1")); - ASSERT_EQ(std::string(200000, '2'), Get("big2")); - ASSERT_EQ(std::string(10, '3'), Get("small3")); - ASSERT_EQ(std::string(10, '4'), Get("small4")); - ASSERT_GT(NumTableFilesAtLevel(0), 1); -} - -TEST(DBTest, CompactionsGenerateMultipleFiles) { - Options options = CurrentOptions(); - options.write_buffer_size = 100000000; // Large write buffer - Reopen(&options); - - Random rnd(301); - - // Write 8MB (80 values, each 100K) - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - std::vector values; - for (int i = 0; i < 80; i++) { - values.push_back(RandomString(&rnd, 100000)); - ASSERT_OK(Put(Key(i), values[i])); - } - - // Reopening moves updates to level-0 - Reopen(&options); - dbfull()->TEST_CompactRange(0, NULL, NULL); - - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - ASSERT_GT(NumTableFilesAtLevel(1), 1); - for (int i = 0; i < 80; i++) { - ASSERT_EQ(Get(Key(i)), values[i]); - } -} - -TEST(DBTest, RepeatedWritesToSameKey) { - Options options = CurrentOptions(); - options.env = env_; - options.write_buffer_size = 100000; // Small write buffer - Reopen(&options); - - // We must have at most one file per level except for level-0, - // which may have up to kL0_StopWritesTrigger files. - const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger; - - Random rnd(301); - std::string value = RandomString(&rnd, 2 * options.write_buffer_size); - for (int i = 0; i < 5 * kMaxFiles; i++) { - Put("key", value); - ASSERT_LE(TotalTableFiles(), kMaxFiles); - fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles()); - } -} - -TEST(DBTest, SparseMerge) { - Options options = CurrentOptions(); - options.compression = kNoCompression; - Reopen(&options); - - FillLevels("A", "Z"); - - // Suppose there is: - // small amount of data with prefix A - // large amount of data with prefix B - // small amount of data with prefix C - // and that recent updates have made small changes to all three prefixes. - // Check that we do not do a compaction that merges all of B in one shot. - const std::string value(1000, 'x'); - Put("A", "va"); - // Write approximately 100MB of "B" values - for (int i = 0; i < 100000; i++) { - char key[100]; - snprintf(key, sizeof(key), "B%010d", i); - Put(key, value); - } - Put("C", "vc"); - dbfull()->TEST_CompactMemTable(); - dbfull()->TEST_CompactRange(0, NULL, NULL); - - // Make sparse update - Put("A", "va2"); - Put("B100", "bvalue2"); - Put("C", "vc2"); - dbfull()->TEST_CompactMemTable(); - - // Compactions should not cause us to create a situation where - // a file overlaps too much data at the next level. - ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); - dbfull()->TEST_CompactRange(0, NULL, NULL); - ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); - dbfull()->TEST_CompactRange(1, NULL, NULL); - ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); -} - -static bool Between(uint64_t val, uint64_t low, uint64_t high) { - bool result = (val >= low) && (val <= high); - if (!result) { - fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", - (unsigned long long)(val), - (unsigned long long)(low), - (unsigned long long)(high)); - } - return result; -} - -TEST(DBTest, ApproximateSizes) { - do { - Options options = CurrentOptions(); - options.write_buffer_size = 100000000; // Large write buffer - options.compression = kNoCompression; - DestroyAndReopen(); - - ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); - Reopen(&options); - ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); - - // Write 8MB (80 values, each 100K) - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - const int N = 80; - static const int S1 = 100000; - static const int S2 = 105000; // Allow some expansion from metadata - Random rnd(301); - for (int i = 0; i < N; i++) { - ASSERT_OK(Put(Key(i), RandomString(&rnd, S1))); - } - - // 0 because GetApproximateSizes() does not account for memtable space - ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); - - // Check sizes across recovery by reopening a few times - for (int run = 0; run < 3; run++) { - Reopen(&options); - - for (int compact_start = 0; compact_start < N; compact_start += 10) { - for (int i = 0; i < N; i += 10) { - ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i)); - ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1))); - ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10)); - } - ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50)); - ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50)); - - std::string cstart_str = Key(compact_start); - std::string cend_str = Key(compact_start + 9); - Slice cstart = cstart_str; - Slice cend = cend_str; - dbfull()->TEST_CompactRange(0, &cstart, &cend); - } - - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - ASSERT_GT(NumTableFilesAtLevel(1), 0); - } - } while (ChangeOptions()); -} - -TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { - do { - Options options = CurrentOptions(); - options.compression = kNoCompression; - Reopen(); - - Random rnd(301); - std::string big1 = RandomString(&rnd, 100000); - ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(2), big1)); - ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(4), big1)); - ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); - ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); - - // Check sizes across recovery by reopening a few times - for (int run = 0; run < 3; run++) { - Reopen(&options); - - ASSERT_TRUE(Between(Size("", Key(0)), 0, 0)); - ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000)); - ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000)); - ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000)); - ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000)); - ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000)); - ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000)); - ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000)); - ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000)); - - ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000)); - - dbfull()->TEST_CompactRange(0, NULL, NULL); - } - } while (ChangeOptions()); -} - -TEST(DBTest, IteratorPinsRef) { - Put("foo", "hello"); - - // Get iterator that will yield the current contents of the DB. - Iterator* iter = db_->NewIterator(ReadOptions()); - - // Write to force compactions - Put("foo", "newvalue1"); - for (int i = 0; i < 100; i++) { - ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values - } - Put("foo", "newvalue2"); - - iter->SeekToFirst(); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("foo", iter->key().ToString()); - ASSERT_EQ("hello", iter->value().ToString()); - iter->Next(); - ASSERT_TRUE(!iter->Valid()); - delete iter; -} - -TEST(DBTest, Snapshot) { - do { - Put("foo", "v1"); - const Snapshot* s1 = db_->GetSnapshot(); - Put("foo", "v2"); - const Snapshot* s2 = db_->GetSnapshot(); - Put("foo", "v3"); - const Snapshot* s3 = db_->GetSnapshot(); - - Put("foo", "v4"); - ASSERT_EQ("v1", Get("foo", s1)); - ASSERT_EQ("v2", Get("foo", s2)); - ASSERT_EQ("v3", Get("foo", s3)); - ASSERT_EQ("v4", Get("foo")); - - db_->ReleaseSnapshot(s3); - ASSERT_EQ("v1", Get("foo", s1)); - ASSERT_EQ("v2", Get("foo", s2)); - ASSERT_EQ("v4", Get("foo")); - - db_->ReleaseSnapshot(s1); - ASSERT_EQ("v2", Get("foo", s2)); - ASSERT_EQ("v4", Get("foo")); - - db_->ReleaseSnapshot(s2); - ASSERT_EQ("v4", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, HiddenValuesAreRemoved) { - do { - Random rnd(301); - FillLevels("a", "z"); - - std::string big = RandomString(&rnd, 50000); - Put("foo", big); - Put("pastfoo", "v"); - const Snapshot* snapshot = db_->GetSnapshot(); - Put("foo", "tiny"); - Put("pastfoo2", "v2"); // Advance sequence number one more - - ASSERT_OK(dbfull()->TEST_CompactMemTable()); - ASSERT_GT(NumTableFilesAtLevel(0), 0); - - ASSERT_EQ(big, Get("foo", snapshot)); - ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000)); - db_->ReleaseSnapshot(snapshot); - ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]"); - Slice x("x"); - dbfull()->TEST_CompactRange(0, NULL, &x); - ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - ASSERT_GE(NumTableFilesAtLevel(1), 1); - dbfull()->TEST_CompactRange(1, NULL, &x); - ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); - - ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000)); - } while (ChangeOptions()); -} - -TEST(DBTest, DeletionMarkers1) { - Put("foo", "v1"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level - - // Place a table at level last-1 to prevent merging with preceding mutation - Put("a", "begin"); - Put("z", "end"); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ(NumTableFilesAtLevel(last), 1); - ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); - - Delete("foo"); - Put("foo", "v2"); - ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 - ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); - Slice z("z"); - dbfull()->TEST_CompactRange(last-2, NULL, &z); - // DEL eliminated, but v1 remains because we aren't compacting that level - // (DEL can be eliminated because v2 hides v1). - ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]"); - dbfull()->TEST_CompactRange(last-1, NULL, NULL); - // Merging last-1 w/ last, so we are the base level for "foo", so - // DEL is removed. (as is v1). - ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]"); -} - -TEST(DBTest, DeletionMarkers2) { - Put("foo", "v1"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level - - // Place a table at level last-1 to prevent merging with preceding mutation - Put("a", "begin"); - Put("z", "end"); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ(NumTableFilesAtLevel(last), 1); - ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); - - Delete("foo"); - ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 - ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); - dbfull()->TEST_CompactRange(last-2, NULL, NULL); - // DEL kept: "last" file overlaps - ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); - dbfull()->TEST_CompactRange(last-1, NULL, NULL); - // Merging last-1 w/ last, so we are the base level for "foo", so - // DEL is removed. (as is v1). - ASSERT_EQ(AllEntriesFor("foo"), "[ ]"); -} - -TEST(DBTest, OverlapInLevel0) { - do { - ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config"; - - // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. - ASSERT_OK(Put("100", "v100")); - ASSERT_OK(Put("999", "v999")); - dbfull()->TEST_CompactMemTable(); - ASSERT_OK(Delete("100")); - ASSERT_OK(Delete("999")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("0,1,1", FilesPerLevel()); - - // Make files spanning the following ranges in level-0: - // files[0] 200 .. 900 - // files[1] 300 .. 500 - // Note that files are sorted by smallest key. - ASSERT_OK(Put("300", "v300")); - ASSERT_OK(Put("500", "v500")); - dbfull()->TEST_CompactMemTable(); - ASSERT_OK(Put("200", "v200")); - ASSERT_OK(Put("600", "v600")); - ASSERT_OK(Put("900", "v900")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("2,1,1", FilesPerLevel()); - - // Compact away the placeholder files we created initially - dbfull()->TEST_CompactRange(1, NULL, NULL); - dbfull()->TEST_CompactRange(2, NULL, NULL); - ASSERT_EQ("2", FilesPerLevel()); - - // Do a memtable compaction. Before bug-fix, the compaction would - // not detect the overlap with level-0 files and would incorrectly place - // the deletion in a deeper level. - ASSERT_OK(Delete("600")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("3", FilesPerLevel()); - ASSERT_EQ("NOT_FOUND", Get("600")); - } while (ChangeOptions()); -} - -TEST(DBTest, L0_CompactionBug_Issue44_a) { - Reopen(); - ASSERT_OK(Put("b", "v")); - Reopen(); - ASSERT_OK(Delete("b")); - ASSERT_OK(Delete("a")); - Reopen(); - ASSERT_OK(Delete("a")); - Reopen(); - ASSERT_OK(Put("a", "v")); - Reopen(); - Reopen(); - ASSERT_EQ("(a->v)", Contents()); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish - ASSERT_EQ("(a->v)", Contents()); -} - -TEST(DBTest, L0_CompactionBug_Issue44_b) { - Reopen(); - Put("",""); - Reopen(); - Delete("e"); - Put("",""); - Reopen(); - Put("c", "cv"); - Reopen(); - Put("",""); - Reopen(); - Put("",""); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish - Reopen(); - Put("d","dv"); - Reopen(); - Put("",""); - Reopen(); - Delete("d"); - Delete("b"); - Reopen(); - ASSERT_EQ("(->)(c->cv)", Contents()); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish - ASSERT_EQ("(->)(c->cv)", Contents()); -} - -TEST(DBTest, ComparatorCheck) { - class NewComparator : public Comparator { - public: - virtual const char* Name() const { return "leveldb.NewComparator"; } - virtual int Compare(const Slice& a, const Slice& b) const { - return BytewiseComparator()->Compare(a, b); - } - virtual void FindShortestSeparator(std::string* s, const Slice& l) const { - BytewiseComparator()->FindShortestSeparator(s, l); - } - virtual void FindShortSuccessor(std::string* key) const { - BytewiseComparator()->FindShortSuccessor(key); - } - }; - NewComparator cmp; - Options new_options = CurrentOptions(); - new_options.comparator = &cmp; - Status s = TryReopen(&new_options); - ASSERT_TRUE(!s.ok()); - ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos) - << s.ToString(); -} - -TEST(DBTest, CustomComparator) { - class NumberComparator : public Comparator { - public: - virtual const char* Name() const { return "test.NumberComparator"; } - virtual int Compare(const Slice& a, const Slice& b) const { - return ToNumber(a) - ToNumber(b); - } - virtual void FindShortestSeparator(std::string* s, const Slice& l) const { - ToNumber(*s); // Check format - ToNumber(l); // Check format - } - virtual void FindShortSuccessor(std::string* key) const { - ToNumber(*key); // Check format - } - private: - static int ToNumber(const Slice& x) { - // Check that there are no extra characters. - ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']') - << EscapeString(x); - int val; - char ignored; - ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1) - << EscapeString(x); - return val; - } - }; - NumberComparator cmp; - Options new_options = CurrentOptions(); - new_options.create_if_missing = true; - new_options.comparator = &cmp; - new_options.filter_policy = NULL; // Cannot use bloom filters - new_options.write_buffer_size = 1000; // Compact more often - DestroyAndReopen(&new_options); - ASSERT_OK(Put("[10]", "ten")); - ASSERT_OK(Put("[0x14]", "twenty")); - for (int i = 0; i < 2; i++) { - ASSERT_EQ("ten", Get("[10]")); - ASSERT_EQ("ten", Get("[0xa]")); - ASSERT_EQ("twenty", Get("[20]")); - ASSERT_EQ("twenty", Get("[0x14]")); - ASSERT_EQ("NOT_FOUND", Get("[15]")); - ASSERT_EQ("NOT_FOUND", Get("[0xf]")); - Compact("[0]", "[9999]"); - } - - for (int run = 0; run < 2; run++) { - for (int i = 0; i < 1000; i++) { - char buf[100]; - snprintf(buf, sizeof(buf), "[%d]", i*10); - ASSERT_OK(Put(buf, buf)); - } - Compact("[0]", "[1000000]"); - } -} - -TEST(DBTest, ManualCompaction) { - ASSERT_EQ(config::kMaxMemCompactLevel, 2) - << "Need to update this test to match kMaxMemCompactLevel"; - - MakeTables(3, "p", "q"); - ASSERT_EQ("1,1,1", FilesPerLevel()); - - // Compaction range falls before files - Compact("", "c"); - ASSERT_EQ("1,1,1", FilesPerLevel()); - - // Compaction range falls after files - Compact("r", "z"); - ASSERT_EQ("1,1,1", FilesPerLevel()); - - // Compaction range overlaps files - Compact("p1", "p9"); - ASSERT_EQ("0,0,1", FilesPerLevel()); - - // Populate a different range - MakeTables(3, "c", "e"); - ASSERT_EQ("1,1,2", FilesPerLevel()); - - // Compact just the new range - Compact("b", "f"); - ASSERT_EQ("0,0,2", FilesPerLevel()); - - // Compact all - MakeTables(1, "a", "z"); - ASSERT_EQ("0,1,2", FilesPerLevel()); - db_->CompactRange(NULL, NULL); - ASSERT_EQ("0,0,1", FilesPerLevel()); -} - -TEST(DBTest, DBOpen_Options) { - std::string dbname = test::TmpDir() + "/db_options_test"; - DestroyDB(dbname, Options()); - - // Does not exist, and create_if_missing == false: error - DB* db = NULL; - Options opts; - opts.create_if_missing = false; - Status s = DB::Open(opts, dbname, &db); - ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL); - ASSERT_TRUE(db == NULL); - - // Does not exist, and create_if_missing == true: OK - opts.create_if_missing = true; - s = DB::Open(opts, dbname, &db); - ASSERT_OK(s); - ASSERT_TRUE(db != NULL); - - delete db; - db = NULL; - - // Does exist, and error_if_exists == true: error - opts.create_if_missing = false; - opts.error_if_exists = true; - s = DB::Open(opts, dbname, &db); - ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL); - ASSERT_TRUE(db == NULL); - - // Does exist, and error_if_exists == false: OK - opts.create_if_missing = true; - opts.error_if_exists = false; - s = DB::Open(opts, dbname, &db); - ASSERT_OK(s); - ASSERT_TRUE(db != NULL); - - delete db; - db = NULL; -} - -TEST(DBTest, Locking) { - DB* db2 = NULL; - Status s = DB::Open(CurrentOptions(), dbname_, &db2); - ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db"; -} - -// Check that number of files does not grow when we are out of space -TEST(DBTest, NoSpace) { - Options options = CurrentOptions(); - options.env = env_; - Reopen(&options); - - ASSERT_OK(Put("foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - Compact("a", "z"); - const int num_files = CountFiles(); - env_->no_space_.Release_Store(env_); // Force out-of-space errors - env_->sleep_counter_.Reset(); - for (int i = 0; i < 5; i++) { - for (int level = 0; level < config::kNumLevels-1; level++) { - dbfull()->TEST_CompactRange(level, NULL, NULL); - } - } - env_->no_space_.Release_Store(NULL); - ASSERT_LT(CountFiles(), num_files + 3); - - // Check that compaction attempts slept after errors - ASSERT_GE(env_->sleep_counter_.Read(), 5); -} - -TEST(DBTest, NonWritableFileSystem) { - Options options = CurrentOptions(); - options.write_buffer_size = 1000; - options.env = env_; - Reopen(&options); - ASSERT_OK(Put("foo", "v1")); - env_->non_writable_.Release_Store(env_); // Force errors for new files - std::string big(100000, 'x'); - int errors = 0; - for (int i = 0; i < 20; i++) { - fprintf(stderr, "iter %d; errors %d\n", i, errors); - if (!Put("foo", big).ok()) { - errors++; - env_->SleepForMicroseconds(100000); - } - } - ASSERT_GT(errors, 0); - env_->non_writable_.Release_Store(NULL); -} - -TEST(DBTest, ManifestWriteError) { - // Test for the following problem: - // (a) Compaction produces file F - // (b) Log record containing F is written to MANIFEST file, but Sync() fails - // (c) GC deletes F - // (d) After reopening DB, reads fail since deleted F is named in log record - - // We iterate twice. In the second iteration, everything is the - // same except the log record never makes it to the MANIFEST file. - for (int iter = 0; iter < 2; iter++) { - port::AtomicPointer* error_type = (iter == 0) - ? &env_->manifest_sync_error_ - : &env_->manifest_write_error_; - - // Insert foo=>bar mapping - Options options = CurrentOptions(); - options.env = env_; - options.create_if_missing = true; - options.error_if_exists = false; - DestroyAndReopen(&options); - ASSERT_OK(Put("foo", "bar")); - ASSERT_EQ("bar", Get("foo")); - - // Memtable compaction (will succeed) - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("bar", Get("foo")); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level - - // Merging compaction (will fail) - error_type->Release_Store(env_); - dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail - ASSERT_EQ("bar", Get("foo")); - - // Recovery: should not lose data - error_type->Release_Store(NULL); - Reopen(&options); - ASSERT_EQ("bar", Get("foo")); - } -} - -TEST(DBTest, FilesDeletedAfterCompaction) { - ASSERT_OK(Put("foo", "v2")); - Compact("a", "z"); - const int num_files = CountFiles(); - for (int i = 0; i < 10; i++) { - ASSERT_OK(Put("foo", "v2")); - Compact("a", "z"); - } - ASSERT_EQ(CountFiles(), num_files); -} - -TEST(DBTest, BloomFilter) { - env_->count_random_reads_ = true; - Options options = CurrentOptions(); - options.env = env_; - options.block_cache = NewLRUCache(0); // Prevent cache hits - options.filter_policy = NewBloomFilterPolicy(10); - Reopen(&options); - - // Populate multiple layers - const int N = 10000; - for (int i = 0; i < N; i++) { - ASSERT_OK(Put(Key(i), Key(i))); - } - Compact("a", "z"); - for (int i = 0; i < N; i += 100) { - ASSERT_OK(Put(Key(i), Key(i))); - } - dbfull()->TEST_CompactMemTable(); - - // Prevent auto compactions triggered by seeks - env_->delay_sstable_sync_.Release_Store(env_); - - // Lookup present keys. Should rarely read from small sstable. - env_->random_read_counter_.Reset(); - for (int i = 0; i < N; i++) { - ASSERT_EQ(Key(i), Get(Key(i))); - } - int reads = env_->random_read_counter_.Read(); - fprintf(stderr, "%d present => %d reads\n", N, reads); - ASSERT_GE(reads, N); - ASSERT_LE(reads, N + 2*N/100); - - // Lookup present keys. Should rarely read from either sstable. - env_->random_read_counter_.Reset(); - for (int i = 0; i < N; i++) { - ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing")); - } - reads = env_->random_read_counter_.Read(); - fprintf(stderr, "%d missing => %d reads\n", N, reads); - ASSERT_LE(reads, 3*N/100); - - env_->delay_sstable_sync_.Release_Store(NULL); - Close(); - delete options.block_cache; - delete options.filter_policy; -} - -// Multi-threaded test: -namespace { - -static const int kNumThreads = 4; -static const int kTestSeconds = 10; -static const int kNumKeys = 1000; - -struct MTState { - DBTest* test; - port::AtomicPointer stop; - port::AtomicPointer counter[kNumThreads]; - port::AtomicPointer thread_done[kNumThreads]; -}; - -struct MTThread { - MTState* state; - int id; -}; - -static void MTThreadBody(void* arg) { - MTThread* t = reinterpret_cast(arg); - int id = t->id; - DB* db = t->state->test->db_; - uintptr_t counter = 0; - fprintf(stderr, "... starting thread %d\n", id); - Random rnd(1000 + id); - std::string value; - char valbuf[1500]; - while (t->state->stop.Acquire_Load() == NULL) { - t->state->counter[id].Release_Store(reinterpret_cast(counter)); - - int key = rnd.Uniform(kNumKeys); - char keybuf[20]; - snprintf(keybuf, sizeof(keybuf), "%016d", key); - - if (rnd.OneIn(2)) { - // Write values of the form . - // We add some padding for force compactions. - snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", - key, id, static_cast(counter)); - ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf))); - } else { - // Read a value and verify that it matches the pattern written above. - Status s = db->Get(ReadOptions(), Slice(keybuf), &value); - if (s.IsNotFound()) { - // Key has not yet been written - } else { - // Check that the writer thread counter is >= the counter in the value - ASSERT_OK(s); - int k, w, c; - ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value; - ASSERT_EQ(k, key); - ASSERT_GE(w, 0); - ASSERT_LT(w, kNumThreads); - ASSERT_LE(c, reinterpret_cast( - t->state->counter[w].Acquire_Load())); - } - } - counter++; - } - t->state->thread_done[id].Release_Store(t); - fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter)); -} - -} // namespace - -TEST(DBTest, MultiThreaded) { - do { - // Initialize state - MTState mt; - mt.test = this; - mt.stop.Release_Store(0); - for (int id = 0; id < kNumThreads; id++) { - mt.counter[id].Release_Store(0); - mt.thread_done[id].Release_Store(0); - } - - // Start threads - MTThread thread[kNumThreads]; - for (int id = 0; id < kNumThreads; id++) { - thread[id].state = &mt; - thread[id].id = id; - env_->StartThread(MTThreadBody, &thread[id]); - } - - // Let them run for a while - env_->SleepForMicroseconds(kTestSeconds * 1000000); - - // Stop the threads and wait for them to finish - mt.stop.Release_Store(&mt); - for (int id = 0; id < kNumThreads; id++) { - while (mt.thread_done[id].Acquire_Load() == NULL) { - env_->SleepForMicroseconds(100000); - } - } - } while (ChangeOptions()); -} - -namespace { -typedef std::map KVMap; -} - -class ModelDB: public DB { - public: - class ModelSnapshot : public Snapshot { - public: - KVMap map_; - }; - - explicit ModelDB(const Options& options): options_(options) { } - ~ModelDB() { } - virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { - return DB::Put(o, k, v); - } - virtual Status Delete(const WriteOptions& o, const Slice& key) { - return DB::Delete(o, key); - } - virtual Status Get(const ReadOptions& options, - const Slice& key, std::string* value) { - assert(false); // Not implemented - return Status::NotFound(key); - } - virtual Iterator* NewIterator(const ReadOptions& options) { - if (options.snapshot == NULL) { - KVMap* saved = new KVMap; - *saved = map_; - return new ModelIter(saved, true); - } else { - const KVMap* snapshot_state = - &(reinterpret_cast(options.snapshot)->map_); - return new ModelIter(snapshot_state, false); - } - } - virtual const Snapshot* GetSnapshot() { - ModelSnapshot* snapshot = new ModelSnapshot; - snapshot->map_ = map_; - return snapshot; - } - - virtual void ReleaseSnapshot(const Snapshot* snapshot) { - delete reinterpret_cast(snapshot); - } - virtual Status Write(const WriteOptions& options, WriteBatch* batch) { - class Handler : public WriteBatch::Handler { - public: - KVMap* map_; - virtual void Put(const Slice& key, const Slice& value) { - (*map_)[key.ToString()] = value.ToString(); - } - virtual void Delete(const Slice& key) { - map_->erase(key.ToString()); - } - }; - Handler handler; - handler.map_ = &map_; - return batch->Iterate(&handler); - } - - virtual bool GetProperty(const Slice& property, std::string* value) { - return false; - } - virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) { - for (int i = 0; i < n; i++) { - sizes[i] = 0; - } - } - virtual void CompactRange(const Slice* start, const Slice* end) { - } - - private: - class ModelIter: public Iterator { - public: - ModelIter(const KVMap* map, bool owned) - : map_(map), owned_(owned), iter_(map_->end()) { - } - ~ModelIter() { - if (owned_) delete map_; - } - virtual bool Valid() const { return iter_ != map_->end(); } - virtual void SeekToFirst() { iter_ = map_->begin(); } - virtual void SeekToLast() { - if (map_->empty()) { - iter_ = map_->end(); - } else { - iter_ = map_->find(map_->rbegin()->first); - } - } - virtual void Seek(const Slice& k) { - iter_ = map_->lower_bound(k.ToString()); - } - virtual void Next() { ++iter_; } - virtual void Prev() { --iter_; } - virtual Slice key() const { return iter_->first; } - virtual Slice value() const { return iter_->second; } - virtual Status status() const { return Status::OK(); } - private: - const KVMap* const map_; - const bool owned_; // Do we own map_ - KVMap::const_iterator iter_; - }; - const Options options_; - KVMap map_; -}; - -static std::string RandomKey(Random* rnd) { - int len = (rnd->OneIn(3) - ? 1 // Short sometimes to encourage collisions - : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10))); - return test::RandomKey(rnd, len); -} - -static bool CompareIterators(int step, - DB* model, - DB* db, - const Snapshot* model_snap, - const Snapshot* db_snap) { - ReadOptions options; - options.snapshot = model_snap; - Iterator* miter = model->NewIterator(options); - options.snapshot = db_snap; - Iterator* dbiter = db->NewIterator(options); - bool ok = true; - int count = 0; - for (miter->SeekToFirst(), dbiter->SeekToFirst(); - ok && miter->Valid() && dbiter->Valid(); - miter->Next(), dbiter->Next()) { - count++; - if (miter->key().compare(dbiter->key()) != 0) { - fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", - step, - EscapeString(miter->key()).c_str(), - EscapeString(dbiter->key()).c_str()); - ok = false; - break; - } - - if (miter->value().compare(dbiter->value()) != 0) { - fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n", - step, - EscapeString(miter->key()).c_str(), - EscapeString(miter->value()).c_str(), - EscapeString(miter->value()).c_str()); - ok = false; - } - } - - if (ok) { - if (miter->Valid() != dbiter->Valid()) { - fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n", - step, miter->Valid(), dbiter->Valid()); - ok = false; - } - } - fprintf(stderr, "%d entries compared: ok=%d\n", count, ok); - delete miter; - delete dbiter; - return ok; -} - -TEST(DBTest, Randomized) { - Random rnd(test::RandomSeed()); - do { - ModelDB model(CurrentOptions()); - const int N = 10000; - const Snapshot* model_snap = NULL; - const Snapshot* db_snap = NULL; - std::string k, v; - for (int step = 0; step < N; step++) { - if (step % 100 == 0) { - fprintf(stderr, "Step %d of %d\n", step, N); - } - // TODO(sanjay): Test Get() works - int p = rnd.Uniform(100); - if (p < 45) { // Put - k = RandomKey(&rnd); - v = RandomString(&rnd, - rnd.OneIn(20) - ? 100 + rnd.Uniform(100) - : rnd.Uniform(8)); - ASSERT_OK(model.Put(WriteOptions(), k, v)); - ASSERT_OK(db_->Put(WriteOptions(), k, v)); - - } else if (p < 90) { // Delete - k = RandomKey(&rnd); - ASSERT_OK(model.Delete(WriteOptions(), k)); - ASSERT_OK(db_->Delete(WriteOptions(), k)); - - - } else { // Multi-element batch - WriteBatch b; - const int num = rnd.Uniform(8); - for (int i = 0; i < num; i++) { - if (i == 0 || !rnd.OneIn(10)) { - k = RandomKey(&rnd); - } else { - // Periodically re-use the same key from the previous iter, so - // we have multiple entries in the write batch for the same key - } - if (rnd.OneIn(2)) { - v = RandomString(&rnd, rnd.Uniform(10)); - b.Put(k, v); - } else { - b.Delete(k); - } - } - ASSERT_OK(model.Write(WriteOptions(), &b)); - ASSERT_OK(db_->Write(WriteOptions(), &b)); - } - - if ((step % 100) == 0) { - ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); - ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap)); - // Save a snapshot from each DB this time that we'll use next - // time we compare things, to make sure the current state is - // preserved with the snapshot - if (model_snap != NULL) model.ReleaseSnapshot(model_snap); - if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); - - Reopen(); - ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); - - model_snap = model.GetSnapshot(); - db_snap = db_->GetSnapshot(); - } - } - if (model_snap != NULL) model.ReleaseSnapshot(model_snap); - if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); - } while (ChangeOptions()); -} - -std::string MakeKey(unsigned int num) { - char buf[30]; - snprintf(buf, sizeof(buf), "%016u", num); - return std::string(buf); -} - -void BM_LogAndApply(int iters, int num_base_files) { - std::string dbname = test::TmpDir() + "/leveldb_test_benchmark"; - DestroyDB(dbname, Options()); - - DB* db = NULL; - Options opts; - opts.create_if_missing = true; - Status s = DB::Open(opts, dbname, &db); - ASSERT_OK(s); - ASSERT_TRUE(db != NULL); - - delete db; - db = NULL; - - Env* env = Env::Default(); - - port::Mutex mu; - MutexLock l(&mu); - - InternalKeyComparator cmp(BytewiseComparator()); - Options options; - VersionSet vset(dbname, &options, NULL, &cmp); - ASSERT_OK(vset.Recover()); - VersionEdit vbase; - uint64_t fnum = 1; - for (int i = 0; i < num_base_files; i++) { - InternalKey start(MakeKey(2*fnum), 1, kTypeValue); - InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); - vbase.AddFile(2, fnum++, 1 /* file size */, start, limit); - } - ASSERT_OK(vset.LogAndApply(&vbase, &mu)); - - uint64_t start_micros = env->NowMicros(); - - for (int i = 0; i < iters; i++) { - VersionEdit vedit; - vedit.DeleteFile(2, fnum); - InternalKey start(MakeKey(2*fnum), 1, kTypeValue); - InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); - vedit.AddFile(2, fnum++, 1 /* file size */, start, limit); - vset.LogAndApply(&vedit, &mu); - } - uint64_t stop_micros = env->NowMicros(); - unsigned int us = stop_micros - start_micros; - char buf[16]; - snprintf(buf, sizeof(buf), "%d", num_base_files); - fprintf(stderr, - "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", - buf, iters, us, ((float)us) / iters); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - if (argc > 1 && std::string(argv[1]) == "--benchmark") { - leveldb::BM_LogAndApply(1000, 1); - leveldb::BM_LogAndApply(1000, 100); - leveldb::BM_LogAndApply(1000, 10000); - leveldb::BM_LogAndApply(100, 100000); - return 0; - } - - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/dbformat.cc b/src/leveldb/db/dbformat.cc deleted file mode 100644 index 28e11b398..000000000 --- a/src/leveldb/db/dbformat.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "db/dbformat.h" -#include "port/port.h" -#include "util/coding.h" - -namespace leveldb { - -static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { - assert(seq <= kMaxSequenceNumber); - assert(t <= kValueTypeForSeek); - return (seq << 8) | t; -} - -void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { - result->append(key.user_key.data(), key.user_key.size()); - PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); -} - -std::string ParsedInternalKey::DebugString() const { - char buf[50]; - snprintf(buf, sizeof(buf), "' @ %llu : %d", - (unsigned long long) sequence, - int(type)); - std::string result = "'"; - result += user_key.ToString(); - result += buf; - return result; -} - -std::string InternalKey::DebugString() const { - std::string result; - ParsedInternalKey parsed; - if (ParseInternalKey(rep_, &parsed)) { - result = parsed.DebugString(); - } else { - result = "(bad)"; - result.append(EscapeString(rep_)); - } - return result; -} - -const char* InternalKeyComparator::Name() const { - return "leveldb.InternalKeyComparator"; -} - -int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { - // Order by: - // increasing user key (according to user-supplied comparator) - // decreasing sequence number - // decreasing type (though sequence# should be enough to disambiguate) - int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); - if (r == 0) { - const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); - const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); - if (anum > bnum) { - r = -1; - } else if (anum < bnum) { - r = +1; - } - } - return r; -} - -void InternalKeyComparator::FindShortestSeparator( - std::string* start, - const Slice& limit) const { - // Attempt to shorten the user portion of the key - Slice user_start = ExtractUserKey(*start); - Slice user_limit = ExtractUserKey(limit); - std::string tmp(user_start.data(), user_start.size()); - user_comparator_->FindShortestSeparator(&tmp, user_limit); - if (tmp.size() < user_start.size() && - user_comparator_->Compare(user_start, tmp) < 0) { - // User key has become shorter physically, but larger logically. - // Tack on the earliest possible number to the shortened user key. - PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); - assert(this->Compare(*start, tmp) < 0); - assert(this->Compare(tmp, limit) < 0); - start->swap(tmp); - } -} - -void InternalKeyComparator::FindShortSuccessor(std::string* key) const { - Slice user_key = ExtractUserKey(*key); - std::string tmp(user_key.data(), user_key.size()); - user_comparator_->FindShortSuccessor(&tmp); - if (tmp.size() < user_key.size() && - user_comparator_->Compare(user_key, tmp) < 0) { - // User key has become shorter physically, but larger logically. - // Tack on the earliest possible number to the shortened user key. - PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); - assert(this->Compare(*key, tmp) < 0); - key->swap(tmp); - } -} - -const char* InternalFilterPolicy::Name() const { - return user_policy_->Name(); -} - -void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, - std::string* dst) const { - // We rely on the fact that the code in table.cc does not mind us - // adjusting keys[]. - Slice* mkey = const_cast(keys); - for (int i = 0; i < n; i++) { - mkey[i] = ExtractUserKey(keys[i]); - // TODO(sanjay): Suppress dups? - } - user_policy_->CreateFilter(keys, n, dst); -} - -bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { - return user_policy_->KeyMayMatch(ExtractUserKey(key), f); -} - -LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { - size_t usize = user_key.size(); - size_t needed = usize + 13; // A conservative estimate - char* dst; - if (needed <= sizeof(space_)) { - dst = space_; - } else { - dst = new char[needed]; - } - start_ = dst; - dst = EncodeVarint32(dst, usize + 8); - kstart_ = dst; - memcpy(dst, user_key.data(), usize); - dst += usize; - EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); - dst += 8; - end_ = dst; -} - -} // namespace leveldb diff --git a/src/leveldb/db/dbformat.h b/src/leveldb/db/dbformat.h deleted file mode 100644 index f7f64dafb..000000000 --- a/src/leveldb/db/dbformat.h +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_FORMAT_H_ -#define STORAGE_LEVELDB_DB_FORMAT_H_ - -#include -#include "leveldb/comparator.h" -#include "leveldb/db.h" -#include "leveldb/filter_policy.h" -#include "leveldb/slice.h" -#include "leveldb/table_builder.h" -#include "util/coding.h" -#include "util/logging.h" - -namespace leveldb { - -// Grouping of constants. We may want to make some of these -// parameters set via options. -namespace config { -static const int kNumLevels = 7; - -// Level-0 compaction is started when we hit this many files. -static const int kL0_CompactionTrigger = 4; - -// Soft limit on number of level-0 files. We slow down writes at this point. -static const int kL0_SlowdownWritesTrigger = 8; - -// Maximum number of level-0 files. We stop writes at this point. -static const int kL0_StopWritesTrigger = 12; - -// Maximum level to which a new compacted memtable is pushed if it -// does not create overlap. We try to push to level 2 to avoid the -// relatively expensive level 0=>1 compactions and to avoid some -// expensive manifest file operations. We do not push all the way to -// the largest level since that can generate a lot of wasted disk -// space if the same key space is being repeatedly overwritten. -static const int kMaxMemCompactLevel = 2; - -} // namespace config - -class InternalKey; - -// Value types encoded as the last component of internal keys. -// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk -// data structures. -enum ValueType { - kTypeDeletion = 0x0, - kTypeValue = 0x1 -}; -// kValueTypeForSeek defines the ValueType that should be passed when -// constructing a ParsedInternalKey object for seeking to a particular -// sequence number (since we sort sequence numbers in decreasing order -// and the value type is embedded as the low 8 bits in the sequence -// number in internal keys, we need to use the highest-numbered -// ValueType, not the lowest). -static const ValueType kValueTypeForSeek = kTypeValue; - -typedef uint64_t SequenceNumber; - -// We leave eight bits empty at the bottom so a type and sequence# -// can be packed together into 64-bits. -static const SequenceNumber kMaxSequenceNumber = - ((0x1ull << 56) - 1); - -struct ParsedInternalKey { - Slice user_key; - SequenceNumber sequence; - ValueType type; - - ParsedInternalKey() { } // Intentionally left uninitialized (for speed) - ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) - : user_key(u), sequence(seq), type(t) { } - std::string DebugString() const; -}; - -// Return the length of the encoding of "key". -inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { - return key.user_key.size() + 8; -} - -// Append the serialization of "key" to *result. -extern void AppendInternalKey(std::string* result, - const ParsedInternalKey& key); - -// Attempt to parse an internal key from "internal_key". On success, -// stores the parsed data in "*result", and returns true. -// -// On error, returns false, leaves "*result" in an undefined state. -extern bool ParseInternalKey(const Slice& internal_key, - ParsedInternalKey* result); - -// Returns the user key portion of an internal key. -inline Slice ExtractUserKey(const Slice& internal_key) { - assert(internal_key.size() >= 8); - return Slice(internal_key.data(), internal_key.size() - 8); -} - -inline ValueType ExtractValueType(const Slice& internal_key) { - assert(internal_key.size() >= 8); - const size_t n = internal_key.size(); - uint64_t num = DecodeFixed64(internal_key.data() + n - 8); - unsigned char c = num & 0xff; - return static_cast(c); -} - -// A comparator for internal keys that uses a specified comparator for -// the user key portion and breaks ties by decreasing sequence number. -class InternalKeyComparator : public Comparator { - private: - const Comparator* user_comparator_; - public: - explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { } - virtual const char* Name() const; - virtual int Compare(const Slice& a, const Slice& b) const; - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const; - virtual void FindShortSuccessor(std::string* key) const; - - const Comparator* user_comparator() const { return user_comparator_; } - - int Compare(const InternalKey& a, const InternalKey& b) const; -}; - -// Filter policy wrapper that converts from internal keys to user keys -class InternalFilterPolicy : public FilterPolicy { - private: - const FilterPolicy* const user_policy_; - public: - explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { } - virtual const char* Name() const; - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; -}; - -// Modules in this directory should keep internal keys wrapped inside -// the following class instead of plain strings so that we do not -// incorrectly use string comparisons instead of an InternalKeyComparator. -class InternalKey { - private: - std::string rep_; - public: - InternalKey() { } // Leave rep_ as empty to indicate it is invalid - InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { - AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); - } - - void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } - Slice Encode() const { - assert(!rep_.empty()); - return rep_; - } - - Slice user_key() const { return ExtractUserKey(rep_); } - - void SetFrom(const ParsedInternalKey& p) { - rep_.clear(); - AppendInternalKey(&rep_, p); - } - - void Clear() { rep_.clear(); } - - std::string DebugString() const; -}; - -inline int InternalKeyComparator::Compare( - const InternalKey& a, const InternalKey& b) const { - return Compare(a.Encode(), b.Encode()); -} - -inline bool ParseInternalKey(const Slice& internal_key, - ParsedInternalKey* result) { - const size_t n = internal_key.size(); - if (n < 8) return false; - uint64_t num = DecodeFixed64(internal_key.data() + n - 8); - unsigned char c = num & 0xff; - result->sequence = num >> 8; - result->type = static_cast(c); - result->user_key = Slice(internal_key.data(), n - 8); - return (c <= static_cast(kTypeValue)); -} - -// A helper class useful for DBImpl::Get() -class LookupKey { - public: - // Initialize *this for looking up user_key at a snapshot with - // the specified sequence number. - LookupKey(const Slice& user_key, SequenceNumber sequence); - - ~LookupKey(); - - // Return a key suitable for lookup in a MemTable. - Slice memtable_key() const { return Slice(start_, end_ - start_); } - - // Return an internal key (suitable for passing to an internal iterator) - Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } - - // Return the user key - Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } - - private: - // We construct a char array of the form: - // klength varint32 <-- start_ - // userkey char[klength] <-- kstart_ - // tag uint64 - // <-- end_ - // The array is a suitable MemTable key. - // The suffix starting with "userkey" can be used as an InternalKey. - const char* start_; - const char* kstart_; - const char* end_; - char space_[200]; // Avoid allocation for short keys - - // No copying allowed - LookupKey(const LookupKey&); - void operator=(const LookupKey&); -}; - -inline LookupKey::~LookupKey() { - if (start_ != space_) delete[] start_; -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_FORMAT_H_ diff --git a/src/leveldb/db/dbformat_test.cc b/src/leveldb/db/dbformat_test.cc deleted file mode 100644 index 5d82f5d31..000000000 --- a/src/leveldb/db/dbformat_test.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/dbformat.h" -#include "util/logging.h" -#include "util/testharness.h" - -namespace leveldb { - -static std::string IKey(const std::string& user_key, - uint64_t seq, - ValueType vt) { - std::string encoded; - AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt)); - return encoded; -} - -static std::string Shorten(const std::string& s, const std::string& l) { - std::string result = s; - InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l); - return result; -} - -static std::string ShortSuccessor(const std::string& s) { - std::string result = s; - InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result); - return result; -} - -static void TestKey(const std::string& key, - uint64_t seq, - ValueType vt) { - std::string encoded = IKey(key, seq, vt); - - Slice in(encoded); - ParsedInternalKey decoded("", 0, kTypeValue); - - ASSERT_TRUE(ParseInternalKey(in, &decoded)); - ASSERT_EQ(key, decoded.user_key.ToString()); - ASSERT_EQ(seq, decoded.sequence); - ASSERT_EQ(vt, decoded.type); - - ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded)); -} - -class FormatTest { }; - -TEST(FormatTest, InternalKey_EncodeDecode) { - const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" }; - const uint64_t seq[] = { - 1, 2, 3, - (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1, - (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1, - (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1 - }; - for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) { - for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) { - TestKey(keys[k], seq[s], kTypeValue); - TestKey("hello", 1, kTypeDeletion); - } - } -} - -TEST(FormatTest, InternalKeyShortSeparator) { - // When user keys are same - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 99, kTypeValue))); - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 101, kTypeValue))); - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 100, kTypeValue))); - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 100, kTypeDeletion))); - - // When user keys are misordered - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("bar", 99, kTypeValue))); - - // When user keys are different, but correctly ordered - ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), - Shorten(IKey("foo", 100, kTypeValue), - IKey("hello", 200, kTypeValue))); - - // When start user key is prefix of limit user key - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foobar", 200, kTypeValue))); - - // When limit user key is prefix of start user key - ASSERT_EQ(IKey("foobar", 100, kTypeValue), - Shorten(IKey("foobar", 100, kTypeValue), - IKey("foo", 200, kTypeValue))); -} - -TEST(FormatTest, InternalKeyShortestSuccessor) { - ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), - ShortSuccessor(IKey("foo", 100, kTypeValue))); - ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue), - ShortSuccessor(IKey("\xff\xff", 100, kTypeValue))); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/filename.cc b/src/leveldb/db/filename.cc deleted file mode 100644 index 3c4d49f64..000000000 --- a/src/leveldb/db/filename.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include "db/filename.h" -#include "db/dbformat.h" -#include "leveldb/env.h" -#include "util/logging.h" - -namespace leveldb { - -// A utility routine: write "data" to the named file and Sync() it. -extern Status WriteStringToFileSync(Env* env, const Slice& data, - const std::string& fname); - -static std::string MakeFileName(const std::string& name, uint64_t number, - const char* suffix) { - char buf[100]; - snprintf(buf, sizeof(buf), "/%06llu.%s", - static_cast(number), - suffix); - return name + buf; -} - -std::string LogFileName(const std::string& name, uint64_t number) { - assert(number > 0); - return MakeFileName(name, number, "log"); -} - -std::string TableFileName(const std::string& name, uint64_t number) { - assert(number > 0); - return MakeFileName(name, number, "sst"); -} - -std::string DescriptorFileName(const std::string& dbname, uint64_t number) { - assert(number > 0); - char buf[100]; - snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", - static_cast(number)); - return dbname + buf; -} - -std::string CurrentFileName(const std::string& dbname) { - return dbname + "/CURRENT"; -} - -std::string LockFileName(const std::string& dbname) { - return dbname + "/LOCK"; -} - -std::string TempFileName(const std::string& dbname, uint64_t number) { - assert(number > 0); - return MakeFileName(dbname, number, "dbtmp"); -} - -std::string InfoLogFileName(const std::string& dbname) { - return dbname + "/LOG"; -} - -// Return the name of the old info log file for "dbname". -std::string OldInfoLogFileName(const std::string& dbname) { - return dbname + "/LOG.old"; -} - - -// Owned filenames have the form: -// dbname/CURRENT -// dbname/LOCK -// dbname/LOG -// dbname/LOG.old -// dbname/MANIFEST-[0-9]+ -// dbname/[0-9]+.(log|sst) -bool ParseFileName(const std::string& fname, - uint64_t* number, - FileType* type) { - Slice rest(fname); - if (rest == "CURRENT") { - *number = 0; - *type = kCurrentFile; - } else if (rest == "LOCK") { - *number = 0; - *type = kDBLockFile; - } else if (rest == "LOG" || rest == "LOG.old") { - *number = 0; - *type = kInfoLogFile; - } else if (rest.starts_with("MANIFEST-")) { - rest.remove_prefix(strlen("MANIFEST-")); - uint64_t num; - if (!ConsumeDecimalNumber(&rest, &num)) { - return false; - } - if (!rest.empty()) { - return false; - } - *type = kDescriptorFile; - *number = num; - } else { - // Avoid strtoull() to keep filename format independent of the - // current locale - uint64_t num; - if (!ConsumeDecimalNumber(&rest, &num)) { - return false; - } - Slice suffix = rest; - if (suffix == Slice(".log")) { - *type = kLogFile; - } else if (suffix == Slice(".sst")) { - *type = kTableFile; - } else if (suffix == Slice(".dbtmp")) { - *type = kTempFile; - } else { - return false; - } - *number = num; - } - return true; -} - -Status SetCurrentFile(Env* env, const std::string& dbname, - uint64_t descriptor_number) { - // Remove leading "dbname/" and add newline to manifest file name - std::string manifest = DescriptorFileName(dbname, descriptor_number); - Slice contents = manifest; - assert(contents.starts_with(dbname + "/")); - contents.remove_prefix(dbname.size() + 1); - std::string tmp = TempFileName(dbname, descriptor_number); - Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); - if (s.ok()) { - s = env->RenameFile(tmp, CurrentFileName(dbname)); - } - if (!s.ok()) { - env->DeleteFile(tmp); - } - return s; -} - -} // namespace leveldb diff --git a/src/leveldb/db/filename.h b/src/leveldb/db/filename.h deleted file mode 100644 index d5d09b114..000000000 --- a/src/leveldb/db/filename.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// File names used by DB code - -#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ -#define STORAGE_LEVELDB_DB_FILENAME_H_ - -#include -#include -#include "leveldb/slice.h" -#include "leveldb/status.h" -#include "port/port.h" - -namespace leveldb { - -class Env; - -enum FileType { - kLogFile, - kDBLockFile, - kTableFile, - kDescriptorFile, - kCurrentFile, - kTempFile, - kInfoLogFile // Either the current one, or an old one -}; - -// Return the name of the log file with the specified number -// in the db named by "dbname". The result will be prefixed with -// "dbname". -extern std::string LogFileName(const std::string& dbname, uint64_t number); - -// Return the name of the sstable with the specified number -// in the db named by "dbname". The result will be prefixed with -// "dbname". -extern std::string TableFileName(const std::string& dbname, uint64_t number); - -// Return the name of the descriptor file for the db named by -// "dbname" and the specified incarnation number. The result will be -// prefixed with "dbname". -extern std::string DescriptorFileName(const std::string& dbname, - uint64_t number); - -// Return the name of the current file. This file contains the name -// of the current manifest file. The result will be prefixed with -// "dbname". -extern std::string CurrentFileName(const std::string& dbname); - -// Return the name of the lock file for the db named by -// "dbname". The result will be prefixed with "dbname". -extern std::string LockFileName(const std::string& dbname); - -// Return the name of a temporary file owned by the db named "dbname". -// The result will be prefixed with "dbname". -extern std::string TempFileName(const std::string& dbname, uint64_t number); - -// Return the name of the info log file for "dbname". -extern std::string InfoLogFileName(const std::string& dbname); - -// Return the name of the old info log file for "dbname". -extern std::string OldInfoLogFileName(const std::string& dbname); - -// If filename is a leveldb file, store the type of the file in *type. -// The number encoded in the filename is stored in *number. If the -// filename was successfully parsed, returns true. Else return false. -extern bool ParseFileName(const std::string& filename, - uint64_t* number, - FileType* type); - -// Make the CURRENT file point to the descriptor file with the -// specified number. -extern Status SetCurrentFile(Env* env, const std::string& dbname, - uint64_t descriptor_number); - - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/src/leveldb/db/filename_test.cc b/src/leveldb/db/filename_test.cc deleted file mode 100644 index 47353d6c9..000000000 --- a/src/leveldb/db/filename_test.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/filename.h" - -#include "db/dbformat.h" -#include "port/port.h" -#include "util/logging.h" -#include "util/testharness.h" - -namespace leveldb { - -class FileNameTest { }; - -TEST(FileNameTest, Parse) { - Slice db; - FileType type; - uint64_t number; - - // Successful parses - static struct { - const char* fname; - uint64_t number; - FileType type; - } cases[] = { - { "100.log", 100, kLogFile }, - { "0.log", 0, kLogFile }, - { "0.sst", 0, kTableFile }, - { "CURRENT", 0, kCurrentFile }, - { "LOCK", 0, kDBLockFile }, - { "MANIFEST-2", 2, kDescriptorFile }, - { "MANIFEST-7", 7, kDescriptorFile }, - { "LOG", 0, kInfoLogFile }, - { "LOG.old", 0, kInfoLogFile }, - { "18446744073709551615.log", 18446744073709551615ull, kLogFile }, - }; - for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { - std::string f = cases[i].fname; - ASSERT_TRUE(ParseFileName(f, &number, &type)) << f; - ASSERT_EQ(cases[i].type, type) << f; - ASSERT_EQ(cases[i].number, number) << f; - } - - // Errors - static const char* errors[] = { - "", - "foo", - "foo-dx-100.log", - ".log", - "", - "manifest", - "CURREN", - "CURRENTX", - "MANIFES", - "MANIFEST", - "MANIFEST-", - "XMANIFEST-3", - "MANIFEST-3x", - "LOC", - "LOCKx", - "LO", - "LOGx", - "18446744073709551616.log", - "184467440737095516150.log", - "100", - "100.", - "100.lop" - }; - for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { - std::string f = errors[i]; - ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; - }; -} - -TEST(FileNameTest, Construction) { - uint64_t number; - FileType type; - std::string fname; - - fname = CurrentFileName("foo"); - ASSERT_EQ("foo/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(0, number); - ASSERT_EQ(kCurrentFile, type); - - fname = LockFileName("foo"); - ASSERT_EQ("foo/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(0, number); - ASSERT_EQ(kDBLockFile, type); - - fname = LogFileName("foo", 192); - ASSERT_EQ("foo/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(192, number); - ASSERT_EQ(kLogFile, type); - - fname = TableFileName("bar", 200); - ASSERT_EQ("bar/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(200, number); - ASSERT_EQ(kTableFile, type); - - fname = DescriptorFileName("bar", 100); - ASSERT_EQ("bar/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(100, number); - ASSERT_EQ(kDescriptorFile, type); - - fname = TempFileName("tmp", 999); - ASSERT_EQ("tmp/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(999, number); - ASSERT_EQ(kTempFile, type); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/leveldb_main.cc b/src/leveldb/db/leveldb_main.cc deleted file mode 100644 index 995d76107..000000000 --- a/src/leveldb/db/leveldb_main.cc +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "db/dbformat.h" -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/version_edit.h" -#include "db/write_batch_internal.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "leveldb/options.h" -#include "leveldb/status.h" -#include "leveldb/table.h" -#include "leveldb/write_batch.h" -#include "util/logging.h" - -namespace leveldb { - -namespace { - -bool GuessType(const std::string& fname, FileType* type) { - size_t pos = fname.rfind('/'); - std::string basename; - if (pos == std::string::npos) { - basename = fname; - } else { - basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); - } - uint64_t ignored; - return ParseFileName(basename, &ignored, type); -} - -// Notified when log reader encounters corruption. -class CorruptionReporter : public log::Reader::Reporter { - public: - virtual void Corruption(size_t bytes, const Status& status) { - printf("corruption: %d bytes; %s\n", - static_cast(bytes), - status.ToString().c_str()); - } -}; - -// Print contents of a log file. (*func)() is called on every record. -bool PrintLogContents(Env* env, const std::string& fname, - void (*func)(Slice)) { - SequentialFile* file; - Status s = env->NewSequentialFile(fname, &file); - if (!s.ok()) { - fprintf(stderr, "%s\n", s.ToString().c_str()); - return false; - } - CorruptionReporter reporter; - log::Reader reader(file, &reporter, true, 0); - Slice record; - std::string scratch; - while (reader.ReadRecord(&record, &scratch)) { - printf("--- offset %llu; ", - static_cast(reader.LastRecordOffset())); - (*func)(record); - } - delete file; - return true; -} - -// Called on every item found in a WriteBatch. -class WriteBatchItemPrinter : public WriteBatch::Handler { - public: - uint64_t offset_; - uint64_t sequence_; - - virtual void Put(const Slice& key, const Slice& value) { - printf(" put '%s' '%s'\n", - EscapeString(key).c_str(), - EscapeString(value).c_str()); - } - virtual void Delete(const Slice& key) { - printf(" del '%s'\n", - EscapeString(key).c_str()); - } -}; - - -// Called on every log record (each one of which is a WriteBatch) -// found in a kLogFile. -static void WriteBatchPrinter(Slice record) { - if (record.size() < 12) { - printf("log record length %d is too small\n", - static_cast(record.size())); - return; - } - WriteBatch batch; - WriteBatchInternal::SetContents(&batch, record); - printf("sequence %llu\n", - static_cast(WriteBatchInternal::Sequence(&batch))); - WriteBatchItemPrinter batch_item_printer; - Status s = batch.Iterate(&batch_item_printer); - if (!s.ok()) { - printf(" error: %s\n", s.ToString().c_str()); - } -} - -bool DumpLog(Env* env, const std::string& fname) { - return PrintLogContents(env, fname, WriteBatchPrinter); -} - -// Called on every log record (each one of which is a WriteBatch) -// found in a kDescriptorFile. -static void VersionEditPrinter(Slice record) { - VersionEdit edit; - Status s = edit.DecodeFrom(record); - if (!s.ok()) { - printf("%s\n", s.ToString().c_str()); - return; - } - printf("%s", edit.DebugString().c_str()); -} - -bool DumpDescriptor(Env* env, const std::string& fname) { - return PrintLogContents(env, fname, VersionEditPrinter); -} - -bool DumpTable(Env* env, const std::string& fname) { - uint64_t file_size; - RandomAccessFile* file = NULL; - Table* table = NULL; - Status s = env->GetFileSize(fname, &file_size); - if (s.ok()) { - s = env->NewRandomAccessFile(fname, &file); - } - if (s.ok()) { - // We use the default comparator, which may or may not match the - // comparator used in this database. However this should not cause - // problems since we only use Table operations that do not require - // any comparisons. In particular, we do not call Seek or Prev. - s = Table::Open(Options(), file, file_size, &table); - } - if (!s.ok()) { - fprintf(stderr, "%s\n", s.ToString().c_str()); - delete table; - delete file; - return false; - } - - ReadOptions ro; - ro.fill_cache = false; - Iterator* iter = table->NewIterator(ro); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - ParsedInternalKey key; - if (!ParseInternalKey(iter->key(), &key)) { - printf("badkey '%s' => '%s'\n", - EscapeString(iter->key()).c_str(), - EscapeString(iter->value()).c_str()); - } else { - char kbuf[20]; - const char* type; - if (key.type == kTypeDeletion) { - type = "del"; - } else if (key.type == kTypeValue) { - type = "val"; - } else { - snprintf(kbuf, sizeof(kbuf), "%d", static_cast(key.type)); - type = kbuf; - } - printf("'%s' @ %8llu : %s => '%s'\n", - EscapeString(key.user_key).c_str(), - static_cast(key.sequence), - type, - EscapeString(iter->value()).c_str()); - } - } - s = iter->status(); - if (!s.ok()) { - printf("iterator error: %s\n", s.ToString().c_str()); - } - - delete iter; - delete table; - delete file; - return true; -} - -bool DumpFile(Env* env, const std::string& fname) { - FileType ftype; - if (!GuessType(fname, &ftype)) { - fprintf(stderr, "%s: unknown file type\n", fname.c_str()); - return false; - } - switch (ftype) { - case kLogFile: return DumpLog(env, fname); - case kDescriptorFile: return DumpDescriptor(env, fname); - case kTableFile: return DumpTable(env, fname); - - default: { - fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str()); - break; - } - } - return false; -} - -bool HandleDumpCommand(Env* env, char** files, int num) { - bool ok = true; - for (int i = 0; i < num; i++) { - ok &= DumpFile(env, files[i]); - } - return ok; -} - -} -} // namespace leveldb - -static void Usage() { - fprintf( - stderr, - "Usage: leveldbutil command...\n" - " dump files... -- dump contents of specified files\n" - ); -} - -int main(int argc, char** argv) { - leveldb::Env* env = leveldb::Env::Default(); - bool ok = true; - if (argc < 2) { - Usage(); - ok = false; - } else { - std::string command = argv[1]; - if (command == "dump") { - ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); - } else { - Usage(); - ok = false; - } - } - return (ok ? 0 : 1); -} diff --git a/src/leveldb/db/log_format.h b/src/leveldb/db/log_format.h deleted file mode 100644 index 2690cb978..000000000 --- a/src/leveldb/db/log_format.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Log format information shared by reader and writer. -// See ../doc/log_format.txt for more detail. - -#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ -#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ - -namespace leveldb { -namespace log { - -enum RecordType { - // Zero is reserved for preallocated files - kZeroType = 0, - - kFullType = 1, - - // For fragments - kFirstType = 2, - kMiddleType = 3, - kLastType = 4 -}; -static const int kMaxRecordType = kLastType; - -static const int kBlockSize = 32768; - -// Header is checksum (4 bytes), type (1 byte), length (2 bytes). -static const int kHeaderSize = 4 + 1 + 2; - -} // namespace log -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc deleted file mode 100644 index b35f115aa..000000000 --- a/src/leveldb/db/log_reader.cc +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/log_reader.h" - -#include -#include "leveldb/env.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { -namespace log { - -Reader::Reporter::~Reporter() { -} - -Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, - uint64_t initial_offset) - : file_(file), - reporter_(reporter), - checksum_(checksum), - backing_store_(new char[kBlockSize]), - buffer_(), - eof_(false), - last_record_offset_(0), - end_of_buffer_offset_(0), - initial_offset_(initial_offset) { -} - -Reader::~Reader() { - delete[] backing_store_; -} - -bool Reader::SkipToInitialBlock() { - size_t offset_in_block = initial_offset_ % kBlockSize; - uint64_t block_start_location = initial_offset_ - offset_in_block; - - // Don't search a block if we'd be in the trailer - if (offset_in_block > kBlockSize - 6) { - offset_in_block = 0; - block_start_location += kBlockSize; - } - - end_of_buffer_offset_ = block_start_location; - - // Skip to start of first block that can contain the initial record - if (block_start_location > 0) { - Status skip_status = file_->Skip(block_start_location); - if (!skip_status.ok()) { - ReportDrop(block_start_location, skip_status); - return false; - } - } - - return true; -} - -bool Reader::ReadRecord(Slice* record, std::string* scratch) { - if (last_record_offset_ < initial_offset_) { - if (!SkipToInitialBlock()) { - return false; - } - } - - scratch->clear(); - record->clear(); - bool in_fragmented_record = false; - // Record offset of the logical record that we're reading - // 0 is a dummy value to make compilers happy - uint64_t prospective_record_offset = 0; - - Slice fragment; - while (true) { - uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size(); - const unsigned int record_type = ReadPhysicalRecord(&fragment); - switch (record_type) { - case kFullType: - if (in_fragmented_record) { - // Handle bug in earlier versions of log::Writer where - // it could emit an empty kFirstType record at the tail end - // of a block followed by a kFullType or kFirstType record - // at the beginning of the next block. - if (scratch->empty()) { - in_fragmented_record = false; - } else { - ReportCorruption(scratch->size(), "partial record without end(1)"); - } - } - prospective_record_offset = physical_record_offset; - scratch->clear(); - *record = fragment; - last_record_offset_ = prospective_record_offset; - return true; - - case kFirstType: - if (in_fragmented_record) { - // Handle bug in earlier versions of log::Writer where - // it could emit an empty kFirstType record at the tail end - // of a block followed by a kFullType or kFirstType record - // at the beginning of the next block. - if (scratch->empty()) { - in_fragmented_record = false; - } else { - ReportCorruption(scratch->size(), "partial record without end(2)"); - } - } - prospective_record_offset = physical_record_offset; - scratch->assign(fragment.data(), fragment.size()); - in_fragmented_record = true; - break; - - case kMiddleType: - if (!in_fragmented_record) { - ReportCorruption(fragment.size(), - "missing start of fragmented record(1)"); - } else { - scratch->append(fragment.data(), fragment.size()); - } - break; - - case kLastType: - if (!in_fragmented_record) { - ReportCorruption(fragment.size(), - "missing start of fragmented record(2)"); - } else { - scratch->append(fragment.data(), fragment.size()); - *record = Slice(*scratch); - last_record_offset_ = prospective_record_offset; - return true; - } - break; - - case kEof: - if (in_fragmented_record) { - ReportCorruption(scratch->size(), "partial record without end(3)"); - scratch->clear(); - } - return false; - - case kBadRecord: - if (in_fragmented_record) { - ReportCorruption(scratch->size(), "error in middle of record"); - in_fragmented_record = false; - scratch->clear(); - } - break; - - default: { - char buf[40]; - snprintf(buf, sizeof(buf), "unknown record type %u", record_type); - ReportCorruption( - (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), - buf); - in_fragmented_record = false; - scratch->clear(); - break; - } - } - } - return false; -} - -uint64_t Reader::LastRecordOffset() { - return last_record_offset_; -} - -void Reader::ReportCorruption(size_t bytes, const char* reason) { - ReportDrop(bytes, Status::Corruption(reason)); -} - -void Reader::ReportDrop(size_t bytes, const Status& reason) { - if (reporter_ != NULL && - end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { - reporter_->Corruption(bytes, reason); - } -} - -unsigned int Reader::ReadPhysicalRecord(Slice* result) { - while (true) { - if (buffer_.size() < kHeaderSize) { - if (!eof_) { - // Last read was a full read, so this is a trailer to skip - buffer_.clear(); - Status status = file_->Read(kBlockSize, &buffer_, backing_store_); - end_of_buffer_offset_ += buffer_.size(); - if (!status.ok()) { - buffer_.clear(); - ReportDrop(kBlockSize, status); - eof_ = true; - return kEof; - } else if (buffer_.size() < kBlockSize) { - eof_ = true; - } - continue; - } else if (buffer_.size() == 0) { - // End of file - return kEof; - } else { - size_t drop_size = buffer_.size(); - buffer_.clear(); - ReportCorruption(drop_size, "truncated record at end of file"); - return kEof; - } - } - - // Parse the header - const char* header = buffer_.data(); - const uint32_t a = static_cast(header[4]) & 0xff; - const uint32_t b = static_cast(header[5]) & 0xff; - const unsigned int type = header[6]; - const uint32_t length = a | (b << 8); - if (kHeaderSize + length > buffer_.size()) { - size_t drop_size = buffer_.size(); - buffer_.clear(); - ReportCorruption(drop_size, "bad record length"); - return kBadRecord; - } - - if (type == kZeroType && length == 0) { - // Skip zero length record without reporting any drops since - // such records are produced by the mmap based writing code in - // env_posix.cc that preallocates file regions. - buffer_.clear(); - return kBadRecord; - } - - // Check crc - if (checksum_) { - uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); - uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); - if (actual_crc != expected_crc) { - // Drop the rest of the buffer since "length" itself may have - // been corrupted and if we trust it, we could find some - // fragment of a real log record that just happens to look - // like a valid log record. - size_t drop_size = buffer_.size(); - buffer_.clear(); - ReportCorruption(drop_size, "checksum mismatch"); - return kBadRecord; - } - } - - buffer_.remove_prefix(kHeaderSize + length); - - // Skip physical record that started before initial_offset_ - if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < - initial_offset_) { - result->clear(); - return kBadRecord; - } - - *result = Slice(header + kHeaderSize, length); - return type; - } -} - -} // namespace log -} // namespace leveldb diff --git a/src/leveldb/db/log_reader.h b/src/leveldb/db/log_reader.h deleted file mode 100644 index 82d4bee68..000000000 --- a/src/leveldb/db/log_reader.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_ -#define STORAGE_LEVELDB_DB_LOG_READER_H_ - -#include - -#include "db/log_format.h" -#include "leveldb/slice.h" -#include "leveldb/status.h" - -namespace leveldb { - -class SequentialFile; - -namespace log { - -class Reader { - public: - // Interface for reporting errors. - class Reporter { - public: - virtual ~Reporter(); - - // Some corruption was detected. "size" is the approximate number - // of bytes dropped due to the corruption. - virtual void Corruption(size_t bytes, const Status& status) = 0; - }; - - // Create a reader that will return log records from "*file". - // "*file" must remain live while this Reader is in use. - // - // If "reporter" is non-NULL, it is notified whenever some data is - // dropped due to a detected corruption. "*reporter" must remain - // live while this Reader is in use. - // - // If "checksum" is true, verify checksums if available. - // - // The Reader will start reading at the first record located at physical - // position >= initial_offset within the file. - Reader(SequentialFile* file, Reporter* reporter, bool checksum, - uint64_t initial_offset); - - ~Reader(); - - // Read the next record into *record. Returns true if read - // successfully, false if we hit end of the input. May use - // "*scratch" as temporary storage. The contents filled in *record - // will only be valid until the next mutating operation on this - // reader or the next mutation to *scratch. - bool ReadRecord(Slice* record, std::string* scratch); - - // Returns the physical offset of the last record returned by ReadRecord. - // - // Undefined before the first call to ReadRecord. - uint64_t LastRecordOffset(); - - private: - SequentialFile* const file_; - Reporter* const reporter_; - bool const checksum_; - char* const backing_store_; - Slice buffer_; - bool eof_; // Last Read() indicated EOF by returning < kBlockSize - - // Offset of the last record returned by ReadRecord. - uint64_t last_record_offset_; - // Offset of the first location past the end of buffer_. - uint64_t end_of_buffer_offset_; - - // Offset at which to start looking for the first record to return - uint64_t const initial_offset_; - - // Extend record types with the following special values - enum { - kEof = kMaxRecordType + 1, - // Returned whenever we find an invalid physical record. - // Currently there are three situations in which this happens: - // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) - // * The record is a 0-length record (No drop is reported) - // * The record is below constructor's initial_offset (No drop is reported) - kBadRecord = kMaxRecordType + 2 - }; - - // Skips all blocks that are completely before "initial_offset_". - // - // Returns true on success. Handles reporting. - bool SkipToInitialBlock(); - - // Return type, or one of the preceding special values - unsigned int ReadPhysicalRecord(Slice* result); - - // Reports dropped bytes to the reporter. - // buffer_ must be updated to remove the dropped bytes prior to invocation. - void ReportCorruption(size_t bytes, const char* reason); - void ReportDrop(size_t bytes, const Status& reason); - - // No copying allowed - Reader(const Reader&); - void operator=(const Reader&); -}; - -} // namespace log -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc deleted file mode 100644 index 4c5cf8757..000000000 --- a/src/leveldb/db/log_test.cc +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "leveldb/env.h" -#include "util/coding.h" -#include "util/crc32c.h" -#include "util/random.h" -#include "util/testharness.h" - -namespace leveldb { -namespace log { - -// Construct a string of the specified length made out of the supplied -// partial string. -static std::string BigString(const std::string& partial_string, size_t n) { - std::string result; - while (result.size() < n) { - result.append(partial_string); - } - result.resize(n); - return result; -} - -// Construct a string from a number -static std::string NumberString(int n) { - char buf[50]; - snprintf(buf, sizeof(buf), "%d.", n); - return std::string(buf); -} - -// Return a skewed potentially long string -static std::string RandomSkewedString(int i, Random* rnd) { - return BigString(NumberString(i), rnd->Skewed(17)); -} - -class LogTest { - private: - class StringDest : public WritableFile { - public: - std::string contents_; - - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - virtual Status Append(const Slice& slice) { - contents_.append(slice.data(), slice.size()); - return Status::OK(); - } - }; - - class StringSource : public SequentialFile { - public: - Slice contents_; - bool force_error_; - bool returned_partial_; - StringSource() : force_error_(false), returned_partial_(false) { } - - virtual Status Read(size_t n, Slice* result, char* scratch) { - ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error"; - - if (force_error_) { - force_error_ = false; - returned_partial_ = true; - return Status::Corruption("read error"); - } - - if (contents_.size() < n) { - n = contents_.size(); - returned_partial_ = true; - } - *result = Slice(contents_.data(), n); - contents_.remove_prefix(n); - return Status::OK(); - } - - virtual Status Skip(uint64_t n) { - if (n > contents_.size()) { - contents_.clear(); - return Status::NotFound("in-memory file skipepd past end"); - } - - contents_.remove_prefix(n); - - return Status::OK(); - } - }; - - class ReportCollector : public Reader::Reporter { - public: - size_t dropped_bytes_; - std::string message_; - - ReportCollector() : dropped_bytes_(0) { } - virtual void Corruption(size_t bytes, const Status& status) { - dropped_bytes_ += bytes; - message_.append(status.ToString()); - } - }; - - StringDest dest_; - StringSource source_; - ReportCollector report_; - bool reading_; - Writer writer_; - Reader reader_; - - // Record metadata for testing initial offset functionality - static size_t initial_offset_record_sizes_[]; - static uint64_t initial_offset_last_record_offsets_[]; - - public: - LogTest() : reading_(false), - writer_(&dest_), - reader_(&source_, &report_, true/*checksum*/, - 0/*initial_offset*/) { - } - - void Write(const std::string& msg) { - ASSERT_TRUE(!reading_) << "Write() after starting to read"; - writer_.AddRecord(Slice(msg)); - } - - size_t WrittenBytes() const { - return dest_.contents_.size(); - } - - std::string Read() { - if (!reading_) { - reading_ = true; - source_.contents_ = Slice(dest_.contents_); - } - std::string scratch; - Slice record; - if (reader_.ReadRecord(&record, &scratch)) { - return record.ToString(); - } else { - return "EOF"; - } - } - - void IncrementByte(int offset, int delta) { - dest_.contents_[offset] += delta; - } - - void SetByte(int offset, char new_byte) { - dest_.contents_[offset] = new_byte; - } - - void ShrinkSize(int bytes) { - dest_.contents_.resize(dest_.contents_.size() - bytes); - } - - void FixChecksum(int header_offset, int len) { - // Compute crc of type/len/data - uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len); - crc = crc32c::Mask(crc); - EncodeFixed32(&dest_.contents_[header_offset], crc); - } - - void ForceError() { - source_.force_error_ = true; - } - - size_t DroppedBytes() const { - return report_.dropped_bytes_; - } - - std::string ReportMessage() const { - return report_.message_; - } - - // Returns OK iff recorded error message contains "msg" - std::string MatchError(const std::string& msg) const { - if (report_.message_.find(msg) == std::string::npos) { - return report_.message_; - } else { - return "OK"; - } - } - - void WriteInitialOffsetLog() { - for (int i = 0; i < 4; i++) { - std::string record(initial_offset_record_sizes_[i], - static_cast('a' + i)); - Write(record); - } - } - - void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { - WriteInitialOffsetLog(); - reading_ = true; - source_.contents_ = Slice(dest_.contents_); - Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, - WrittenBytes() + offset_past_end); - Slice record; - std::string scratch; - ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch)); - delete offset_reader; - } - - void CheckInitialOffsetRecord(uint64_t initial_offset, - int expected_record_offset) { - WriteInitialOffsetLog(); - reading_ = true; - source_.contents_ = Slice(dest_.contents_); - Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, - initial_offset); - Slice record; - std::string scratch; - ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); - ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], - record.size()); - ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], - offset_reader->LastRecordOffset()); - ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); - delete offset_reader; - } - -}; - -size_t LogTest::initial_offset_record_sizes_[] = - {10000, // Two sizable records in first block - 10000, - 2 * log::kBlockSize - 1000, // Span three blocks - 1}; - -uint64_t LogTest::initial_offset_last_record_offsets_[] = - {0, - kHeaderSize + 10000, - 2 * (kHeaderSize + 10000), - 2 * (kHeaderSize + 10000) + - (2 * log::kBlockSize - 1000) + 3 * kHeaderSize}; - - -TEST(LogTest, Empty) { - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, ReadWrite) { - Write("foo"); - Write("bar"); - Write(""); - Write("xxxx"); - ASSERT_EQ("foo", Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("", Read()); - ASSERT_EQ("xxxx", Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ("EOF", Read()); // Make sure reads at eof work -} - -TEST(LogTest, ManyBlocks) { - for (int i = 0; i < 100000; i++) { - Write(NumberString(i)); - } - for (int i = 0; i < 100000; i++) { - ASSERT_EQ(NumberString(i), Read()); - } - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, Fragmentation) { - Write("small"); - Write(BigString("medium", 50000)); - Write(BigString("large", 100000)); - ASSERT_EQ("small", Read()); - ASSERT_EQ(BigString("medium", 50000), Read()); - ASSERT_EQ(BigString("large", 100000), Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, MarginalTrailer) { - // Make a trailer that is exactly the same length as an empty record. - const int n = kBlockSize - 2*kHeaderSize; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); - Write(""); - Write("bar"); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("", Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, MarginalTrailer2) { - // Make a trailer that is exactly the same length as an empty record. - const int n = kBlockSize - 2*kHeaderSize; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); - Write("bar"); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(0, DroppedBytes()); - ASSERT_EQ("", ReportMessage()); -} - -TEST(LogTest, ShortTrailer) { - const int n = kBlockSize - 2*kHeaderSize + 4; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); - Write(""); - Write("bar"); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("", Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, AlignedEof) { - const int n = kBlockSize - 2*kHeaderSize + 4; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, RandomRead) { - const int N = 500; - Random write_rnd(301); - for (int i = 0; i < N; i++) { - Write(RandomSkewedString(i, &write_rnd)); - } - Random read_rnd(301); - for (int i = 0; i < N; i++) { - ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read()); - } - ASSERT_EQ("EOF", Read()); -} - -// Tests of all the error paths in log_reader.cc follow: - -TEST(LogTest, ReadError) { - Write("foo"); - ForceError(); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(kBlockSize, DroppedBytes()); - ASSERT_EQ("OK", MatchError("read error")); -} - -TEST(LogTest, BadRecordType) { - Write("foo"); - // Type is stored in header[6] - IncrementByte(6, 100); - FixChecksum(0, 3); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("unknown record type")); -} - -TEST(LogTest, TruncatedTrailingRecord) { - Write("foo"); - ShrinkSize(4); // Drop all payload as well as a header byte - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(kHeaderSize - 1, DroppedBytes()); - ASSERT_EQ("OK", MatchError("truncated record at end of file")); -} - -TEST(LogTest, BadLength) { - Write("foo"); - ShrinkSize(1); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(kHeaderSize + 2, DroppedBytes()); - ASSERT_EQ("OK", MatchError("bad record length")); -} - -TEST(LogTest, ChecksumMismatch) { - Write("foo"); - IncrementByte(0, 10); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(10, DroppedBytes()); - ASSERT_EQ("OK", MatchError("checksum mismatch")); -} - -TEST(LogTest, UnexpectedMiddleType) { - Write("foo"); - SetByte(6, kMiddleType); - FixChecksum(0, 3); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("missing start")); -} - -TEST(LogTest, UnexpectedLastType) { - Write("foo"); - SetByte(6, kLastType); - FixChecksum(0, 3); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("missing start")); -} - -TEST(LogTest, UnexpectedFullType) { - Write("foo"); - Write("bar"); - SetByte(6, kFirstType); - FixChecksum(0, 3); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("partial record without end")); -} - -TEST(LogTest, UnexpectedFirstType) { - Write("foo"); - Write(BigString("bar", 100000)); - SetByte(6, kFirstType); - FixChecksum(0, 3); - ASSERT_EQ(BigString("bar", 100000), Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("partial record without end")); -} - -TEST(LogTest, ErrorJoinsRecords) { - // Consider two fragmented records: - // first(R1) last(R1) first(R2) last(R2) - // where the middle two fragments disappear. We do not want - // first(R1),last(R2) to get joined and returned as a valid record. - - // Write records that span two blocks - Write(BigString("foo", kBlockSize)); - Write(BigString("bar", kBlockSize)); - Write("correct"); - - // Wipe the middle block - for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) { - SetByte(offset, 'x'); - } - - ASSERT_EQ("correct", Read()); - ASSERT_EQ("EOF", Read()); - const int dropped = DroppedBytes(); - ASSERT_LE(dropped, 2*kBlockSize + 100); - ASSERT_GE(dropped, 2*kBlockSize); -} - -TEST(LogTest, ReadStart) { - CheckInitialOffsetRecord(0, 0); -} - -TEST(LogTest, ReadSecondOneOff) { - CheckInitialOffsetRecord(1, 1); -} - -TEST(LogTest, ReadSecondTenThousand) { - CheckInitialOffsetRecord(10000, 1); -} - -TEST(LogTest, ReadSecondStart) { - CheckInitialOffsetRecord(10007, 1); -} - -TEST(LogTest, ReadThirdOneOff) { - CheckInitialOffsetRecord(10008, 2); -} - -TEST(LogTest, ReadThirdStart) { - CheckInitialOffsetRecord(20014, 2); -} - -TEST(LogTest, ReadFourthOneOff) { - CheckInitialOffsetRecord(20015, 3); -} - -TEST(LogTest, ReadFourthFirstBlockTrailer) { - CheckInitialOffsetRecord(log::kBlockSize - 4, 3); -} - -TEST(LogTest, ReadFourthMiddleBlock) { - CheckInitialOffsetRecord(log::kBlockSize + 1, 3); -} - -TEST(LogTest, ReadFourthLastBlock) { - CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3); -} - -TEST(LogTest, ReadFourthStart) { - CheckInitialOffsetRecord( - 2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, - 3); -} - -TEST(LogTest, ReadEnd) { - CheckOffsetPastEndReturnsNoRecords(0); -} - -TEST(LogTest, ReadPastEnd) { - CheckOffsetPastEndReturnsNoRecords(5); -} - -} // namespace log -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/log_writer.cc b/src/leveldb/db/log_writer.cc deleted file mode 100644 index 2da99ac08..000000000 --- a/src/leveldb/db/log_writer.cc +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/log_writer.h" - -#include -#include "leveldb/env.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { -namespace log { - -Writer::Writer(WritableFile* dest) - : dest_(dest), - block_offset_(0) { - for (int i = 0; i <= kMaxRecordType; i++) { - char t = static_cast(i); - type_crc_[i] = crc32c::Value(&t, 1); - } -} - -Writer::~Writer() { -} - -Status Writer::AddRecord(const Slice& slice) { - const char* ptr = slice.data(); - size_t left = slice.size(); - - // Fragment the record if necessary and emit it. Note that if slice - // is empty, we still want to iterate once to emit a single - // zero-length record - Status s; - bool begin = true; - do { - const int leftover = kBlockSize - block_offset_; - assert(leftover >= 0); - if (leftover < kHeaderSize) { - // Switch to a new block - if (leftover > 0) { - // Fill the trailer (literal below relies on kHeaderSize being 7) - assert(kHeaderSize == 7); - dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); - } - block_offset_ = 0; - } - - // Invariant: we never leave < kHeaderSize bytes in a block. - assert(kBlockSize - block_offset_ - kHeaderSize >= 0); - - const size_t avail = kBlockSize - block_offset_ - kHeaderSize; - const size_t fragment_length = (left < avail) ? left : avail; - - RecordType type; - const bool end = (left == fragment_length); - if (begin && end) { - type = kFullType; - } else if (begin) { - type = kFirstType; - } else if (end) { - type = kLastType; - } else { - type = kMiddleType; - } - - s = EmitPhysicalRecord(type, ptr, fragment_length); - ptr += fragment_length; - left -= fragment_length; - begin = false; - } while (s.ok() && left > 0); - return s; -} - -Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { - assert(n <= 0xffff); // Must fit in two bytes - assert(block_offset_ + kHeaderSize + n <= kBlockSize); - - // Format the header - char buf[kHeaderSize]; - buf[4] = static_cast(n & 0xff); - buf[5] = static_cast(n >> 8); - buf[6] = static_cast(t); - - // Compute the crc of the record type and the payload. - uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); - crc = crc32c::Mask(crc); // Adjust for storage - EncodeFixed32(buf, crc); - - // Write the header and the payload - Status s = dest_->Append(Slice(buf, kHeaderSize)); - if (s.ok()) { - s = dest_->Append(Slice(ptr, n)); - if (s.ok()) { - s = dest_->Flush(); - } - } - block_offset_ += kHeaderSize + n; - return s; -} - -} // namespace log -} // namespace leveldb diff --git a/src/leveldb/db/log_writer.h b/src/leveldb/db/log_writer.h deleted file mode 100644 index a3a954d96..000000000 --- a/src/leveldb/db/log_writer.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_ -#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ - -#include -#include "db/log_format.h" -#include "leveldb/slice.h" -#include "leveldb/status.h" - -namespace leveldb { - -class WritableFile; - -namespace log { - -class Writer { - public: - // Create a writer that will append data to "*dest". - // "*dest" must be initially empty. - // "*dest" must remain live while this Writer is in use. - explicit Writer(WritableFile* dest); - ~Writer(); - - Status AddRecord(const Slice& slice); - - private: - WritableFile* dest_; - int block_offset_; // Current offset in block - - // crc32c values for all supported record types. These are - // pre-computed to reduce the overhead of computing the crc of the - // record type stored in the header. - uint32_t type_crc_[kMaxRecordType + 1]; - - Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); - - // No copying allowed - Writer(const Writer&); - void operator=(const Writer&); -}; - -} // namespace log -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc deleted file mode 100644 index bfec0a7e7..000000000 --- a/src/leveldb/db/memtable.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/memtable.h" -#include "db/dbformat.h" -#include "leveldb/comparator.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "util/coding.h" - -namespace leveldb { - -static Slice GetLengthPrefixedSlice(const char* data) { - uint32_t len; - const char* p = data; - p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted - return Slice(p, len); -} - -MemTable::MemTable(const InternalKeyComparator& cmp) - : comparator_(cmp), - refs_(0), - table_(comparator_, &arena_) { -} - -MemTable::~MemTable() { - assert(refs_ == 0); -} - -size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } - -int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) - const { - // Internal keys are encoded as length-prefixed strings. - Slice a = GetLengthPrefixedSlice(aptr); - Slice b = GetLengthPrefixedSlice(bptr); - return comparator.Compare(a, b); -} - -// Encode a suitable internal key target for "target" and return it. -// Uses *scratch as scratch space, and the returned pointer will point -// into this scratch space. -static const char* EncodeKey(std::string* scratch, const Slice& target) { - scratch->clear(); - PutVarint32(scratch, target.size()); - scratch->append(target.data(), target.size()); - return scratch->data(); -} - -class MemTableIterator: public Iterator { - public: - explicit MemTableIterator(MemTable::Table* table) : iter_(table) { } - - virtual bool Valid() const { return iter_.Valid(); } - virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } - virtual void SeekToFirst() { iter_.SeekToFirst(); } - virtual void SeekToLast() { iter_.SeekToLast(); } - virtual void Next() { iter_.Next(); } - virtual void Prev() { iter_.Prev(); } - virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } - virtual Slice value() const { - Slice key_slice = GetLengthPrefixedSlice(iter_.key()); - return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); - } - - virtual Status status() const { return Status::OK(); } - - private: - MemTable::Table::Iterator iter_; - std::string tmp_; // For passing to EncodeKey - - // No copying allowed - MemTableIterator(const MemTableIterator&); - void operator=(const MemTableIterator&); -}; - -Iterator* MemTable::NewIterator() { - return new MemTableIterator(&table_); -} - -void MemTable::Add(SequenceNumber s, ValueType type, - const Slice& key, - const Slice& value) { - // Format of an entry is concatenation of: - // key_size : varint32 of internal_key.size() - // key bytes : char[internal_key.size()] - // value_size : varint32 of value.size() - // value bytes : char[value.size()] - size_t key_size = key.size(); - size_t val_size = value.size(); - size_t internal_key_size = key_size + 8; - const size_t encoded_len = - VarintLength(internal_key_size) + internal_key_size + - VarintLength(val_size) + val_size; - char* buf = arena_.Allocate(encoded_len); - char* p = EncodeVarint32(buf, internal_key_size); - memcpy(p, key.data(), key_size); - p += key_size; - EncodeFixed64(p, (s << 8) | type); - p += 8; - p = EncodeVarint32(p, val_size); - memcpy(p, value.data(), val_size); - assert((p + val_size) - buf == encoded_len); - table_.Insert(buf); -} - -bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { - Slice memkey = key.memtable_key(); - Table::Iterator iter(&table_); - iter.Seek(memkey.data()); - if (iter.Valid()) { - // entry format is: - // klength varint32 - // userkey char[klength] - // tag uint64 - // vlength varint32 - // value char[vlength] - // Check that it belongs to same user key. We do not check the - // sequence number since the Seek() call above should have skipped - // all entries with overly large sequence numbers. - const char* entry = iter.key(); - uint32_t key_length; - const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); - if (comparator_.comparator.user_comparator()->Compare( - Slice(key_ptr, key_length - 8), - key.user_key()) == 0) { - // Correct user key - const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); - switch (static_cast(tag & 0xff)) { - case kTypeValue: { - Slice v = GetLengthPrefixedSlice(key_ptr + key_length); - value->assign(v.data(), v.size()); - return true; - } - case kTypeDeletion: - *s = Status::NotFound(Slice()); - return true; - } - } - } - return false; -} - -} // namespace leveldb diff --git a/src/leveldb/db/memtable.h b/src/leveldb/db/memtable.h deleted file mode 100644 index 92e90bb09..000000000 --- a/src/leveldb/db/memtable.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_ -#define STORAGE_LEVELDB_DB_MEMTABLE_H_ - -#include -#include "leveldb/db.h" -#include "db/dbformat.h" -#include "db/skiplist.h" -#include "util/arena.h" - -namespace leveldb { - -class InternalKeyComparator; -class Mutex; -class MemTableIterator; - -class MemTable { - public: - // MemTables are reference counted. The initial reference count - // is zero and the caller must call Ref() at least once. - explicit MemTable(const InternalKeyComparator& comparator); - - // Increase reference count. - void Ref() { ++refs_; } - - // Drop reference count. Delete if no more references exist. - void Unref() { - --refs_; - assert(refs_ >= 0); - if (refs_ <= 0) { - delete this; - } - } - - // Returns an estimate of the number of bytes of data in use by this - // data structure. - // - // REQUIRES: external synchronization to prevent simultaneous - // operations on the same MemTable. - size_t ApproximateMemoryUsage(); - - // Return an iterator that yields the contents of the memtable. - // - // The caller must ensure that the underlying MemTable remains live - // while the returned iterator is live. The keys returned by this - // iterator are internal keys encoded by AppendInternalKey in the - // db/format.{h,cc} module. - Iterator* NewIterator(); - - // Add an entry into memtable that maps key to value at the - // specified sequence number and with the specified type. - // Typically value will be empty if type==kTypeDeletion. - void Add(SequenceNumber seq, ValueType type, - const Slice& key, - const Slice& value); - - // If memtable contains a value for key, store it in *value and return true. - // If memtable contains a deletion for key, store a NotFound() error - // in *status and return true. - // Else, return false. - bool Get(const LookupKey& key, std::string* value, Status* s); - - private: - ~MemTable(); // Private since only Unref() should be used to delete it - - struct KeyComparator { - const InternalKeyComparator comparator; - explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { } - int operator()(const char* a, const char* b) const; - }; - friend class MemTableIterator; - friend class MemTableBackwardIterator; - - typedef SkipList Table; - - KeyComparator comparator_; - int refs_; - Arena arena_; - Table table_; - - // No copying allowed - MemTable(const MemTable&); - void operator=(const MemTable&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc deleted file mode 100644 index 022d52f3d..000000000 --- a/src/leveldb/db/repair.cc +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// We recover the contents of the descriptor from the other files we find. -// (1) Any log files are first converted to tables -// (2) We scan every table to compute -// (a) smallest/largest for the table -// (b) largest sequence number in the table -// (3) We generate descriptor contents: -// - log number is set to zero -// - next-file-number is set to 1 + largest file number we found -// - last-sequence-number is set to largest sequence# found across -// all tables (see 2c) -// - compaction pointers are cleared -// - every table file is added at level 0 -// -// Possible optimization 1: -// (a) Compute total size and use to pick appropriate max-level M -// (b) Sort tables by largest sequence# in the table -// (c) For each table: if it overlaps earlier table, place in level-0, -// else place in level-M. -// Possible optimization 2: -// Store per-table metadata (smallest, largest, largest-seq#, ...) -// in the table's meta section to speed up ScanTable. - -#include "db/builder.h" -#include "db/db_impl.h" -#include "db/dbformat.h" -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "db/memtable.h" -#include "db/table_cache.h" -#include "db/version_edit.h" -#include "db/write_batch_internal.h" -#include "leveldb/comparator.h" -#include "leveldb/db.h" -#include "leveldb/env.h" - -namespace leveldb { - -namespace { - -class Repairer { - public: - Repairer(const std::string& dbname, const Options& options) - : dbname_(dbname), - env_(options.env), - icmp_(options.comparator), - ipolicy_(options.filter_policy), - options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), - owns_info_log_(options_.info_log != options.info_log), - owns_cache_(options_.block_cache != options.block_cache), - next_file_number_(1) { - // TableCache can be small since we expect each table to be opened once. - table_cache_ = new TableCache(dbname_, &options_, 10); - } - - ~Repairer() { - delete table_cache_; - if (owns_info_log_) { - delete options_.info_log; - } - if (owns_cache_) { - delete options_.block_cache; - } - } - - Status Run() { - Status status = FindFiles(); - if (status.ok()) { - ConvertLogFilesToTables(); - ExtractMetaData(); - status = WriteDescriptor(); - } - if (status.ok()) { - unsigned long long bytes = 0; - for (size_t i = 0; i < tables_.size(); i++) { - bytes += tables_[i].meta.file_size; - } - Log(options_.info_log, - "**** Repaired leveldb %s; " - "recovered %d files; %llu bytes. " - "Some data may have been lost. " - "****", - dbname_.c_str(), - static_cast(tables_.size()), - bytes); - } - return status; - } - - private: - struct TableInfo { - FileMetaData meta; - SequenceNumber max_sequence; - }; - - std::string const dbname_; - Env* const env_; - InternalKeyComparator const icmp_; - InternalFilterPolicy const ipolicy_; - Options const options_; - bool owns_info_log_; - bool owns_cache_; - TableCache* table_cache_; - VersionEdit edit_; - - std::vector manifests_; - std::vector table_numbers_; - std::vector logs_; - std::vector tables_; - uint64_t next_file_number_; - - Status FindFiles() { - std::vector filenames; - Status status = env_->GetChildren(dbname_, &filenames); - if (!status.ok()) { - return status; - } - if (filenames.empty()) { - return Status::IOError(dbname_, "repair found no files"); - } - - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type)) { - if (type == kDescriptorFile) { - manifests_.push_back(filenames[i]); - } else { - if (number + 1 > next_file_number_) { - next_file_number_ = number + 1; - } - if (type == kLogFile) { - logs_.push_back(number); - } else if (type == kTableFile) { - table_numbers_.push_back(number); - } else { - // Ignore other files - } - } - } - } - return status; - } - - void ConvertLogFilesToTables() { - for (size_t i = 0; i < logs_.size(); i++) { - std::string logname = LogFileName(dbname_, logs_[i]); - Status status = ConvertLogToTable(logs_[i]); - if (!status.ok()) { - Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", - (unsigned long long) logs_[i], - status.ToString().c_str()); - } - ArchiveFile(logname); - } - } - - Status ConvertLogToTable(uint64_t log) { - struct LogReporter : public log::Reader::Reporter { - Env* env; - Logger* info_log; - uint64_t lognum; - virtual void Corruption(size_t bytes, const Status& s) { - // We print error messages for corruption, but continue repairing. - Log(info_log, "Log #%llu: dropping %d bytes; %s", - (unsigned long long) lognum, - static_cast(bytes), - s.ToString().c_str()); - } - }; - - // Open the log file - std::string logname = LogFileName(dbname_, log); - SequentialFile* lfile; - Status status = env_->NewSequentialFile(logname, &lfile); - if (!status.ok()) { - return status; - } - - // Create the log reader. - LogReporter reporter; - reporter.env = env_; - reporter.info_log = options_.info_log; - reporter.lognum = log; - // We intentially make log::Reader do checksumming so that - // corruptions cause entire commits to be skipped instead of - // propagating bad information (like overly large sequence - // numbers). - log::Reader reader(lfile, &reporter, false/*do not checksum*/, - 0/*initial_offset*/); - - // Read all the records and add to a memtable - std::string scratch; - Slice record; - WriteBatch batch; - MemTable* mem = new MemTable(icmp_); - mem->Ref(); - int counter = 0; - while (reader.ReadRecord(&record, &scratch)) { - if (record.size() < 12) { - reporter.Corruption( - record.size(), Status::Corruption("log record too small")); - continue; - } - WriteBatchInternal::SetContents(&batch, record); - status = WriteBatchInternal::InsertInto(&batch, mem); - if (status.ok()) { - counter += WriteBatchInternal::Count(&batch); - } else { - Log(options_.info_log, "Log #%llu: ignoring %s", - (unsigned long long) log, - status.ToString().c_str()); - status = Status::OK(); // Keep going with rest of file - } - } - delete lfile; - - // Do not record a version edit for this conversion to a Table - // since ExtractMetaData() will also generate edits. - FileMetaData meta; - meta.number = next_file_number_++; - Iterator* iter = mem->NewIterator(); - status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); - delete iter; - mem->Unref(); - mem = NULL; - if (status.ok()) { - if (meta.file_size > 0) { - table_numbers_.push_back(meta.number); - } - } - Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", - (unsigned long long) log, - counter, - (unsigned long long) meta.number, - status.ToString().c_str()); - return status; - } - - void ExtractMetaData() { - std::vector kept; - for (size_t i = 0; i < table_numbers_.size(); i++) { - TableInfo t; - t.meta.number = table_numbers_[i]; - Status status = ScanTable(&t); - if (!status.ok()) { - std::string fname = TableFileName(dbname_, table_numbers_[i]); - Log(options_.info_log, "Table #%llu: ignoring %s", - (unsigned long long) table_numbers_[i], - status.ToString().c_str()); - ArchiveFile(fname); - } else { - tables_.push_back(t); - } - } - } - - Status ScanTable(TableInfo* t) { - std::string fname = TableFileName(dbname_, t->meta.number); - int counter = 0; - Status status = env_->GetFileSize(fname, &t->meta.file_size); - if (status.ok()) { - Iterator* iter = table_cache_->NewIterator( - ReadOptions(), t->meta.number, t->meta.file_size); - bool empty = true; - ParsedInternalKey parsed; - t->max_sequence = 0; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - Slice key = iter->key(); - if (!ParseInternalKey(key, &parsed)) { - Log(options_.info_log, "Table #%llu: unparsable key %s", - (unsigned long long) t->meta.number, - EscapeString(key).c_str()); - continue; - } - - counter++; - if (empty) { - empty = false; - t->meta.smallest.DecodeFrom(key); - } - t->meta.largest.DecodeFrom(key); - if (parsed.sequence > t->max_sequence) { - t->max_sequence = parsed.sequence; - } - } - if (!iter->status().ok()) { - status = iter->status(); - } - delete iter; - } - Log(options_.info_log, "Table #%llu: %d entries %s", - (unsigned long long) t->meta.number, - counter, - status.ToString().c_str()); - return status; - } - - Status WriteDescriptor() { - std::string tmp = TempFileName(dbname_, 1); - WritableFile* file; - Status status = env_->NewWritableFile(tmp, &file); - if (!status.ok()) { - return status; - } - - SequenceNumber max_sequence = 0; - for (size_t i = 0; i < tables_.size(); i++) { - if (max_sequence < tables_[i].max_sequence) { - max_sequence = tables_[i].max_sequence; - } - } - - edit_.SetComparatorName(icmp_.user_comparator()->Name()); - edit_.SetLogNumber(0); - edit_.SetNextFile(next_file_number_); - edit_.SetLastSequence(max_sequence); - - for (size_t i = 0; i < tables_.size(); i++) { - // TODO(opt): separate out into multiple levels - const TableInfo& t = tables_[i]; - edit_.AddFile(0, t.meta.number, t.meta.file_size, - t.meta.smallest, t.meta.largest); - } - - //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); - { - log::Writer log(file); - std::string record; - edit_.EncodeTo(&record); - status = log.AddRecord(record); - } - if (status.ok()) { - status = file->Close(); - } - delete file; - file = NULL; - - if (!status.ok()) { - env_->DeleteFile(tmp); - } else { - // Discard older manifests - for (size_t i = 0; i < manifests_.size(); i++) { - ArchiveFile(dbname_ + "/" + manifests_[i]); - } - - // Install new manifest - status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); - if (status.ok()) { - status = SetCurrentFile(env_, dbname_, 1); - } else { - env_->DeleteFile(tmp); - } - } - return status; - } - - void ArchiveFile(const std::string& fname) { - // Move into another directory. E.g., for - // dir/foo - // rename to - // dir/lost/foo - const char* slash = strrchr(fname.c_str(), '/'); - std::string new_dir; - if (slash != NULL) { - new_dir.assign(fname.data(), slash - fname.data()); - } - new_dir.append("/lost"); - env_->CreateDir(new_dir); // Ignore error - std::string new_file = new_dir; - new_file.append("/"); - new_file.append((slash == NULL) ? fname.c_str() : slash + 1); - Status s = env_->RenameFile(fname, new_file); - Log(options_.info_log, "Archiving %s: %s\n", - fname.c_str(), s.ToString().c_str()); - } -}; -} // namespace - -Status RepairDB(const std::string& dbname, const Options& options) { - Repairer repairer(dbname, options); - return repairer.Run(); -} - -} // namespace leveldb diff --git a/src/leveldb/db/skiplist.h b/src/leveldb/db/skiplist.h deleted file mode 100644 index af85be6d0..000000000 --- a/src/leveldb/db/skiplist.h +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Thread safety -// ------------- -// -// Writes require external synchronization, most likely a mutex. -// Reads require a guarantee that the SkipList will not be destroyed -// while the read is in progress. Apart from that, reads progress -// without any internal locking or synchronization. -// -// Invariants: -// -// (1) Allocated nodes are never deleted until the SkipList is -// destroyed. This is trivially guaranteed by the code since we -// never delete any skip list nodes. -// -// (2) The contents of a Node except for the next/prev pointers are -// immutable after the Node has been linked into the SkipList. -// Only Insert() modifies the list, and it is careful to initialize -// a node and use release-stores to publish the nodes in one or -// more lists. -// -// ... prev vs. next pointer ordering ... - -#include -#include -#include "port/port.h" -#include "util/arena.h" -#include "util/random.h" - -namespace leveldb { - -class Arena; - -template -class SkipList { - private: - struct Node; - - public: - // Create a new SkipList object that will use "cmp" for comparing keys, - // and will allocate memory using "*arena". Objects allocated in the arena - // must remain allocated for the lifetime of the skiplist object. - explicit SkipList(Comparator cmp, Arena* arena); - - // Insert key into the list. - // REQUIRES: nothing that compares equal to key is currently in the list. - void Insert(const Key& key); - - // Returns true iff an entry that compares equal to key is in the list. - bool Contains(const Key& key) const; - - // Iteration over the contents of a skip list - class Iterator { - public: - // Initialize an iterator over the specified list. - // The returned iterator is not valid. - explicit Iterator(const SkipList* list); - - // Returns true iff the iterator is positioned at a valid node. - bool Valid() const; - - // Returns the key at the current position. - // REQUIRES: Valid() - const Key& key() const; - - // Advances to the next position. - // REQUIRES: Valid() - void Next(); - - // Advances to the previous position. - // REQUIRES: Valid() - void Prev(); - - // Advance to the first entry with a key >= target - void Seek(const Key& target); - - // Position at the first entry in list. - // Final state of iterator is Valid() iff list is not empty. - void SeekToFirst(); - - // Position at the last entry in list. - // Final state of iterator is Valid() iff list is not empty. - void SeekToLast(); - - private: - const SkipList* list_; - Node* node_; - // Intentionally copyable - }; - - private: - enum { kMaxHeight = 12 }; - - // Immutable after construction - Comparator const compare_; - Arena* const arena_; // Arena used for allocations of nodes - - Node* const head_; - - // Modified only by Insert(). Read racily by readers, but stale - // values are ok. - port::AtomicPointer max_height_; // Height of the entire list - - inline int GetMaxHeight() const { - return static_cast( - reinterpret_cast(max_height_.NoBarrier_Load())); - } - - // Read/written only by Insert(). - Random rnd_; - - Node* NewNode(const Key& key, int height); - int RandomHeight(); - bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } - - // Return true if key is greater than the data stored in "n" - bool KeyIsAfterNode(const Key& key, Node* n) const; - - // Return the earliest node that comes at or after key. - // Return NULL if there is no such node. - // - // If prev is non-NULL, fills prev[level] with pointer to previous - // node at "level" for every level in [0..max_height_-1]. - Node* FindGreaterOrEqual(const Key& key, Node** prev) const; - - // Return the latest node with a key < key. - // Return head_ if there is no such node. - Node* FindLessThan(const Key& key) const; - - // Return the last node in the list. - // Return head_ if list is empty. - Node* FindLast() const; - - // No copying allowed - SkipList(const SkipList&); - void operator=(const SkipList&); -}; - -// Implementation details follow -template -struct SkipList::Node { - explicit Node(const Key& k) : key(k) { } - - Key const key; - - // Accessors/mutators for links. Wrapped in methods so we can - // add the appropriate barriers as necessary. - Node* Next(int n) { - assert(n >= 0); - // Use an 'acquire load' so that we observe a fully initialized - // version of the returned Node. - return reinterpret_cast(next_[n].Acquire_Load()); - } - void SetNext(int n, Node* x) { - assert(n >= 0); - // Use a 'release store' so that anybody who reads through this - // pointer observes a fully initialized version of the inserted node. - next_[n].Release_Store(x); - } - - // No-barrier variants that can be safely used in a few locations. - Node* NoBarrier_Next(int n) { - assert(n >= 0); - return reinterpret_cast(next_[n].NoBarrier_Load()); - } - void NoBarrier_SetNext(int n, Node* x) { - assert(n >= 0); - next_[n].NoBarrier_Store(x); - } - - private: - // Array of length equal to the node height. next_[0] is lowest level link. - port::AtomicPointer next_[1]; -}; - -template -typename SkipList::Node* -SkipList::NewNode(const Key& key, int height) { - char* mem = arena_->AllocateAligned( - sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); - return new (mem) Node(key); -} - -template -inline SkipList::Iterator::Iterator(const SkipList* list) { - list_ = list; - node_ = NULL; -} - -template -inline bool SkipList::Iterator::Valid() const { - return node_ != NULL; -} - -template -inline const Key& SkipList::Iterator::key() const { - assert(Valid()); - return node_->key; -} - -template -inline void SkipList::Iterator::Next() { - assert(Valid()); - node_ = node_->Next(0); -} - -template -inline void SkipList::Iterator::Prev() { - // Instead of using explicit "prev" links, we just search for the - // last node that falls before key. - assert(Valid()); - node_ = list_->FindLessThan(node_->key); - if (node_ == list_->head_) { - node_ = NULL; - } -} - -template -inline void SkipList::Iterator::Seek(const Key& target) { - node_ = list_->FindGreaterOrEqual(target, NULL); -} - -template -inline void SkipList::Iterator::SeekToFirst() { - node_ = list_->head_->Next(0); -} - -template -inline void SkipList::Iterator::SeekToLast() { - node_ = list_->FindLast(); - if (node_ == list_->head_) { - node_ = NULL; - } -} - -template -int SkipList::RandomHeight() { - // Increase height with probability 1 in kBranching - static const unsigned int kBranching = 4; - int height = 1; - while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { - height++; - } - assert(height > 0); - assert(height <= kMaxHeight); - return height; -} - -template -bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { - // NULL n is considered infinite - return (n != NULL) && (compare_(n->key, key) < 0); -} - -template -typename SkipList::Node* SkipList::FindGreaterOrEqual(const Key& key, Node** prev) - const { - Node* x = head_; - int level = GetMaxHeight() - 1; - while (true) { - Node* next = x->Next(level); - if (KeyIsAfterNode(key, next)) { - // Keep searching in this list - x = next; - } else { - if (prev != NULL) prev[level] = x; - if (level == 0) { - return next; - } else { - // Switch to next list - level--; - } - } - } -} - -template -typename SkipList::Node* -SkipList::FindLessThan(const Key& key) const { - Node* x = head_; - int level = GetMaxHeight() - 1; - while (true) { - assert(x == head_ || compare_(x->key, key) < 0); - Node* next = x->Next(level); - if (next == NULL || compare_(next->key, key) >= 0) { - if (level == 0) { - return x; - } else { - // Switch to next list - level--; - } - } else { - x = next; - } - } -} - -template -typename SkipList::Node* SkipList::FindLast() - const { - Node* x = head_; - int level = GetMaxHeight() - 1; - while (true) { - Node* next = x->Next(level); - if (next == NULL) { - if (level == 0) { - return x; - } else { - // Switch to next list - level--; - } - } else { - x = next; - } - } -} - -template -SkipList::SkipList(Comparator cmp, Arena* arena) - : compare_(cmp), - arena_(arena), - head_(NewNode(0 /* any key will do */, kMaxHeight)), - max_height_(reinterpret_cast(1)), - rnd_(0xdeadbeef) { - for (int i = 0; i < kMaxHeight; i++) { - head_->SetNext(i, NULL); - } -} - -template -void SkipList::Insert(const Key& key) { - // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() - // here since Insert() is externally synchronized. - Node* prev[kMaxHeight]; - Node* x = FindGreaterOrEqual(key, prev); - - // Our data structure does not allow duplicate insertion - assert(x == NULL || !Equal(key, x->key)); - - int height = RandomHeight(); - if (height > GetMaxHeight()) { - for (int i = GetMaxHeight(); i < height; i++) { - prev[i] = head_; - } - //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); - - // It is ok to mutate max_height_ without any synchronization - // with concurrent readers. A concurrent reader that observes - // the new value of max_height_ will see either the old value of - // new level pointers from head_ (NULL), or a new value set in - // the loop below. In the former case the reader will - // immediately drop to the next level since NULL sorts after all - // keys. In the latter case the reader will use the new node. - max_height_.NoBarrier_Store(reinterpret_cast(height)); - } - - x = NewNode(key, height); - for (int i = 0; i < height; i++) { - // NoBarrier_SetNext() suffices since we will add a barrier when - // we publish a pointer to "x" in prev[i]. - x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); - prev[i]->SetNext(i, x); - } -} - -template -bool SkipList::Contains(const Key& key) const { - Node* x = FindGreaterOrEqual(key, NULL); - if (x != NULL && Equal(key, x->key)) { - return true; - } else { - return false; - } -} - -} // namespace leveldb diff --git a/src/leveldb/db/skiplist_test.cc b/src/leveldb/db/skiplist_test.cc deleted file mode 100644 index c78f4b4fb..000000000 --- a/src/leveldb/db/skiplist_test.cc +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/skiplist.h" -#include -#include "leveldb/env.h" -#include "util/arena.h" -#include "util/hash.h" -#include "util/random.h" -#include "util/testharness.h" - -namespace leveldb { - -typedef uint64_t Key; - -struct Comparator { - int operator()(const Key& a, const Key& b) const { - if (a < b) { - return -1; - } else if (a > b) { - return +1; - } else { - return 0; - } - } -}; - -class SkipTest { }; - -TEST(SkipTest, Empty) { - Arena arena; - Comparator cmp; - SkipList list(cmp, &arena); - ASSERT_TRUE(!list.Contains(10)); - - SkipList::Iterator iter(&list); - ASSERT_TRUE(!iter.Valid()); - iter.SeekToFirst(); - ASSERT_TRUE(!iter.Valid()); - iter.Seek(100); - ASSERT_TRUE(!iter.Valid()); - iter.SeekToLast(); - ASSERT_TRUE(!iter.Valid()); -} - -TEST(SkipTest, InsertAndLookup) { - const int N = 2000; - const int R = 5000; - Random rnd(1000); - std::set keys; - Arena arena; - Comparator cmp; - SkipList list(cmp, &arena); - for (int i = 0; i < N; i++) { - Key key = rnd.Next() % R; - if (keys.insert(key).second) { - list.Insert(key); - } - } - - for (int i = 0; i < R; i++) { - if (list.Contains(i)) { - ASSERT_EQ(keys.count(i), 1); - } else { - ASSERT_EQ(keys.count(i), 0); - } - } - - // Simple iterator tests - { - SkipList::Iterator iter(&list); - ASSERT_TRUE(!iter.Valid()); - - iter.Seek(0); - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*(keys.begin()), iter.key()); - - iter.SeekToFirst(); - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*(keys.begin()), iter.key()); - - iter.SeekToLast(); - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*(keys.rbegin()), iter.key()); - } - - // Forward iteration test - for (int i = 0; i < R; i++) { - SkipList::Iterator iter(&list); - iter.Seek(i); - - // Compare against model iterator - std::set::iterator model_iter = keys.lower_bound(i); - for (int j = 0; j < 3; j++) { - if (model_iter == keys.end()) { - ASSERT_TRUE(!iter.Valid()); - break; - } else { - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*model_iter, iter.key()); - ++model_iter; - iter.Next(); - } - } - } - - // Backward iteration test - { - SkipList::Iterator iter(&list); - iter.SeekToLast(); - - // Compare against model iterator - for (std::set::reverse_iterator model_iter = keys.rbegin(); - model_iter != keys.rend(); - ++model_iter) { - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*model_iter, iter.key()); - iter.Prev(); - } - ASSERT_TRUE(!iter.Valid()); - } -} - -// We want to make sure that with a single writer and multiple -// concurrent readers (with no synchronization other than when a -// reader's iterator is created), the reader always observes all the -// data that was present in the skip list when the iterator was -// constructor. Because insertions are happening concurrently, we may -// also observe new values that were inserted since the iterator was -// constructed, but we should never miss any values that were present -// at iterator construction time. -// -// We generate multi-part keys: -// -// where: -// key is in range [0..K-1] -// gen is a generation number for key -// hash is hash(key,gen) -// -// The insertion code picks a random key, sets gen to be 1 + the last -// generation number inserted for that key, and sets hash to Hash(key,gen). -// -// At the beginning of a read, we snapshot the last inserted -// generation number for each key. We then iterate, including random -// calls to Next() and Seek(). For every key we encounter, we -// check that it is either expected given the initial snapshot or has -// been concurrently added since the iterator started. -class ConcurrentTest { - private: - static const uint32_t K = 4; - - static uint64_t key(Key key) { return (key >> 40); } - static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; } - static uint64_t hash(Key key) { return key & 0xff; } - - static uint64_t HashNumbers(uint64_t k, uint64_t g) { - uint64_t data[2] = { k, g }; - return Hash(reinterpret_cast(data), sizeof(data), 0); - } - - static Key MakeKey(uint64_t k, uint64_t g) { - assert(sizeof(Key) == sizeof(uint64_t)); - assert(k <= K); // We sometimes pass K to seek to the end of the skiplist - assert(g <= 0xffffffffu); - return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff)); - } - - static bool IsValidKey(Key k) { - return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff); - } - - static Key RandomTarget(Random* rnd) { - switch (rnd->Next() % 10) { - case 0: - // Seek to beginning - return MakeKey(0, 0); - case 1: - // Seek to end - return MakeKey(K, 0); - default: - // Seek to middle - return MakeKey(rnd->Next() % K, 0); - } - } - - // Per-key generation - struct State { - port::AtomicPointer generation[K]; - void Set(int k, intptr_t v) { - generation[k].Release_Store(reinterpret_cast(v)); - } - intptr_t Get(int k) { - return reinterpret_cast(generation[k].Acquire_Load()); - } - - State() { - for (int k = 0; k < K; k++) { - Set(k, 0); - } - } - }; - - // Current state of the test - State current_; - - Arena arena_; - - // SkipList is not protected by mu_. We just use a single writer - // thread to modify it. - SkipList list_; - - public: - ConcurrentTest() : list_(Comparator(), &arena_) { } - - // REQUIRES: External synchronization - void WriteStep(Random* rnd) { - const uint32_t k = rnd->Next() % K; - const intptr_t g = current_.Get(k) + 1; - const Key key = MakeKey(k, g); - list_.Insert(key); - current_.Set(k, g); - } - - void ReadStep(Random* rnd) { - // Remember the initial committed state of the skiplist. - State initial_state; - for (int k = 0; k < K; k++) { - initial_state.Set(k, current_.Get(k)); - } - - Key pos = RandomTarget(rnd); - SkipList::Iterator iter(&list_); - iter.Seek(pos); - while (true) { - Key current; - if (!iter.Valid()) { - current = MakeKey(K, 0); - } else { - current = iter.key(); - ASSERT_TRUE(IsValidKey(current)) << current; - } - ASSERT_LE(pos, current) << "should not go backwards"; - - // Verify that everything in [pos,current) was not present in - // initial_state. - while (pos < current) { - ASSERT_LT(key(pos), K) << pos; - - // Note that generation 0 is never inserted, so it is ok if - // <*,0,*> is missing. - ASSERT_TRUE((gen(pos) == 0) || - (gen(pos) > initial_state.Get(key(pos))) - ) << "key: " << key(pos) - << "; gen: " << gen(pos) - << "; initgen: " - << initial_state.Get(key(pos)); - - // Advance to next key in the valid key space - if (key(pos) < key(current)) { - pos = MakeKey(key(pos) + 1, 0); - } else { - pos = MakeKey(key(pos), gen(pos) + 1); - } - } - - if (!iter.Valid()) { - break; - } - - if (rnd->Next() % 2) { - iter.Next(); - pos = MakeKey(key(pos), gen(pos) + 1); - } else { - Key new_target = RandomTarget(rnd); - if (new_target > pos) { - pos = new_target; - iter.Seek(new_target); - } - } - } - } -}; -const uint32_t ConcurrentTest::K; - -// Simple test that does single-threaded testing of the ConcurrentTest -// scaffolding. -TEST(SkipTest, ConcurrentWithoutThreads) { - ConcurrentTest test; - Random rnd(test::RandomSeed()); - for (int i = 0; i < 10000; i++) { - test.ReadStep(&rnd); - test.WriteStep(&rnd); - } -} - -class TestState { - public: - ConcurrentTest t_; - int seed_; - port::AtomicPointer quit_flag_; - - enum ReaderState { - STARTING, - RUNNING, - DONE - }; - - explicit TestState(int s) - : seed_(s), - quit_flag_(NULL), - state_(STARTING), - state_cv_(&mu_) {} - - void Wait(ReaderState s) { - mu_.Lock(); - while (state_ != s) { - state_cv_.Wait(); - } - mu_.Unlock(); - } - - void Change(ReaderState s) { - mu_.Lock(); - state_ = s; - state_cv_.Signal(); - mu_.Unlock(); - } - - private: - port::Mutex mu_; - ReaderState state_; - port::CondVar state_cv_; -}; - -static void ConcurrentReader(void* arg) { - TestState* state = reinterpret_cast(arg); - Random rnd(state->seed_); - int64_t reads = 0; - state->Change(TestState::RUNNING); - while (!state->quit_flag_.Acquire_Load()) { - state->t_.ReadStep(&rnd); - ++reads; - } - state->Change(TestState::DONE); -} - -static void RunConcurrent(int run) { - const int seed = test::RandomSeed() + (run * 100); - Random rnd(seed); - const int N = 1000; - const int kSize = 1000; - for (int i = 0; i < N; i++) { - if ((i % 100) == 0) { - fprintf(stderr, "Run %d of %d\n", i, N); - } - TestState state(seed + 1); - Env::Default()->Schedule(ConcurrentReader, &state); - state.Wait(TestState::RUNNING); - for (int i = 0; i < kSize; i++) { - state.t_.WriteStep(&rnd); - } - state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do - state.Wait(TestState::DONE); - } -} - -TEST(SkipTest, Concurrent1) { RunConcurrent(1); } -TEST(SkipTest, Concurrent2) { RunConcurrent(2); } -TEST(SkipTest, Concurrent3) { RunConcurrent(3); } -TEST(SkipTest, Concurrent4) { RunConcurrent(4); } -TEST(SkipTest, Concurrent5) { RunConcurrent(5); } - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/snapshot.h b/src/leveldb/db/snapshot.h deleted file mode 100644 index e7f8fd2c3..000000000 --- a/src/leveldb/db/snapshot.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ -#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ - -#include "leveldb/db.h" - -namespace leveldb { - -class SnapshotList; - -// Snapshots are kept in a doubly-linked list in the DB. -// Each SnapshotImpl corresponds to a particular sequence number. -class SnapshotImpl : public Snapshot { - public: - SequenceNumber number_; // const after creation - - private: - friend class SnapshotList; - - // SnapshotImpl is kept in a doubly-linked circular list - SnapshotImpl* prev_; - SnapshotImpl* next_; - - SnapshotList* list_; // just for sanity checks -}; - -class SnapshotList { - public: - SnapshotList() { - list_.prev_ = &list_; - list_.next_ = &list_; - } - - bool empty() const { return list_.next_ == &list_; } - SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } - SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } - - const SnapshotImpl* New(SequenceNumber seq) { - SnapshotImpl* s = new SnapshotImpl; - s->number_ = seq; - s->list_ = this; - s->next_ = &list_; - s->prev_ = list_.prev_; - s->prev_->next_ = s; - s->next_->prev_ = s; - return s; - } - - void Delete(const SnapshotImpl* s) { - assert(s->list_ == this); - s->prev_->next_ = s->next_; - s->next_->prev_ = s->prev_; - delete s; - } - - private: - // Dummy head of doubly-linked list of snapshots - SnapshotImpl list_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/src/leveldb/db/table_cache.cc b/src/leveldb/db/table_cache.cc deleted file mode 100644 index 497db2707..000000000 --- a/src/leveldb/db/table_cache.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/table_cache.h" - -#include "db/filename.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "util/coding.h" - -namespace leveldb { - -struct TableAndFile { - RandomAccessFile* file; - Table* table; -}; - -static void DeleteEntry(const Slice& key, void* value) { - TableAndFile* tf = reinterpret_cast(value); - delete tf->table; - delete tf->file; - delete tf; -} - -static void UnrefEntry(void* arg1, void* arg2) { - Cache* cache = reinterpret_cast(arg1); - Cache::Handle* h = reinterpret_cast(arg2); - cache->Release(h); -} - -TableCache::TableCache(const std::string& dbname, - const Options* options, - int entries) - : env_(options->env), - dbname_(dbname), - options_(options), - cache_(NewLRUCache(entries)) { -} - -TableCache::~TableCache() { - delete cache_; -} - -Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, - Cache::Handle** handle) { - Status s; - char buf[sizeof(file_number)]; - EncodeFixed64(buf, file_number); - Slice key(buf, sizeof(buf)); - *handle = cache_->Lookup(key); - if (*handle == NULL) { - std::string fname = TableFileName(dbname_, file_number); - RandomAccessFile* file = NULL; - Table* table = NULL; - s = env_->NewRandomAccessFile(fname, &file); - if (s.ok()) { - s = Table::Open(*options_, file, file_size, &table); - } - - if (!s.ok()) { - assert(table == NULL); - delete file; - // We do not cache error results so that if the error is transient, - // or somebody repairs the file, we recover automatically. - } else { - TableAndFile* tf = new TableAndFile; - tf->file = file; - tf->table = table; - *handle = cache_->Insert(key, tf, 1, &DeleteEntry); - } - } - return s; -} - -Iterator* TableCache::NewIterator(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - Table** tableptr) { - if (tableptr != NULL) { - *tableptr = NULL; - } - - Cache::Handle* handle = NULL; - Status s = FindTable(file_number, file_size, &handle); - if (!s.ok()) { - return NewErrorIterator(s); - } - - Table* table = reinterpret_cast(cache_->Value(handle))->table; - Iterator* result = table->NewIterator(options); - result->RegisterCleanup(&UnrefEntry, cache_, handle); - if (tableptr != NULL) { - *tableptr = table; - } - return result; -} - -Status TableCache::Get(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - const Slice& k, - void* arg, - void (*saver)(void*, const Slice&, const Slice&)) { - Cache::Handle* handle = NULL; - Status s = FindTable(file_number, file_size, &handle); - if (s.ok()) { - Table* t = reinterpret_cast(cache_->Value(handle))->table; - s = t->InternalGet(options, k, arg, saver); - cache_->Release(handle); - } - return s; -} - -void TableCache::Evict(uint64_t file_number) { - char buf[sizeof(file_number)]; - EncodeFixed64(buf, file_number); - cache_->Erase(Slice(buf, sizeof(buf))); -} - -} // namespace leveldb diff --git a/src/leveldb/db/table_cache.h b/src/leveldb/db/table_cache.h deleted file mode 100644 index 8cf4aaf12..000000000 --- a/src/leveldb/db/table_cache.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Thread-safe (provides internal synchronization) - -#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ -#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ - -#include -#include -#include "db/dbformat.h" -#include "leveldb/cache.h" -#include "leveldb/table.h" -#include "port/port.h" - -namespace leveldb { - -class Env; - -class TableCache { - public: - TableCache(const std::string& dbname, const Options* options, int entries); - ~TableCache(); - - // Return an iterator for the specified file number (the corresponding - // file length must be exactly "file_size" bytes). If "tableptr" is - // non-NULL, also sets "*tableptr" to point to the Table object - // underlying the returned iterator, or NULL if no Table object underlies - // the returned iterator. The returned "*tableptr" object is owned by - // the cache and should not be deleted, and is valid for as long as the - // returned iterator is live. - Iterator* NewIterator(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - Table** tableptr = NULL); - - // If a seek to internal key "k" in specified file finds an entry, - // call (*handle_result)(arg, found_key, found_value). - Status Get(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - const Slice& k, - void* arg, - void (*handle_result)(void*, const Slice&, const Slice&)); - - // Evict any entry for the specified file number - void Evict(uint64_t file_number); - - private: - Env* const env_; - const std::string dbname_; - const Options* options_; - Cache* cache_; - - Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/src/leveldb/db/version_edit.cc b/src/leveldb/db/version_edit.cc deleted file mode 100644 index f10a2d58b..000000000 --- a/src/leveldb/db/version_edit.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_edit.h" - -#include "db/version_set.h" -#include "util/coding.h" - -namespace leveldb { - -// Tag numbers for serialized VersionEdit. These numbers are written to -// disk and should not be changed. -enum Tag { - kComparator = 1, - kLogNumber = 2, - kNextFileNumber = 3, - kLastSequence = 4, - kCompactPointer = 5, - kDeletedFile = 6, - kNewFile = 7, - // 8 was used for large value refs - kPrevLogNumber = 9 -}; - -void VersionEdit::Clear() { - comparator_.clear(); - log_number_ = 0; - prev_log_number_ = 0; - last_sequence_ = 0; - next_file_number_ = 0; - has_comparator_ = false; - has_log_number_ = false; - has_prev_log_number_ = false; - has_next_file_number_ = false; - has_last_sequence_ = false; - deleted_files_.clear(); - new_files_.clear(); -} - -void VersionEdit::EncodeTo(std::string* dst) const { - if (has_comparator_) { - PutVarint32(dst, kComparator); - PutLengthPrefixedSlice(dst, comparator_); - } - if (has_log_number_) { - PutVarint32(dst, kLogNumber); - PutVarint64(dst, log_number_); - } - if (has_prev_log_number_) { - PutVarint32(dst, kPrevLogNumber); - PutVarint64(dst, prev_log_number_); - } - if (has_next_file_number_) { - PutVarint32(dst, kNextFileNumber); - PutVarint64(dst, next_file_number_); - } - if (has_last_sequence_) { - PutVarint32(dst, kLastSequence); - PutVarint64(dst, last_sequence_); - } - - for (size_t i = 0; i < compact_pointers_.size(); i++) { - PutVarint32(dst, kCompactPointer); - PutVarint32(dst, compact_pointers_[i].first); // level - PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); - } - - for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); - iter != deleted_files_.end(); - ++iter) { - PutVarint32(dst, kDeletedFile); - PutVarint32(dst, iter->first); // level - PutVarint64(dst, iter->second); // file number - } - - for (size_t i = 0; i < new_files_.size(); i++) { - const FileMetaData& f = new_files_[i].second; - PutVarint32(dst, kNewFile); - PutVarint32(dst, new_files_[i].first); // level - PutVarint64(dst, f.number); - PutVarint64(dst, f.file_size); - PutLengthPrefixedSlice(dst, f.smallest.Encode()); - PutLengthPrefixedSlice(dst, f.largest.Encode()); - } -} - -static bool GetInternalKey(Slice* input, InternalKey* dst) { - Slice str; - if (GetLengthPrefixedSlice(input, &str)) { - dst->DecodeFrom(str); - return true; - } else { - return false; - } -} - -static bool GetLevel(Slice* input, int* level) { - uint32_t v; - if (GetVarint32(input, &v) && - v < config::kNumLevels) { - *level = v; - return true; - } else { - return false; - } -} - -Status VersionEdit::DecodeFrom(const Slice& src) { - Clear(); - Slice input = src; - const char* msg = NULL; - uint32_t tag; - - // Temporary storage for parsing - int level; - uint64_t number; - FileMetaData f; - Slice str; - InternalKey key; - - while (msg == NULL && GetVarint32(&input, &tag)) { - switch (tag) { - case kComparator: - if (GetLengthPrefixedSlice(&input, &str)) { - comparator_ = str.ToString(); - has_comparator_ = true; - } else { - msg = "comparator name"; - } - break; - - case kLogNumber: - if (GetVarint64(&input, &log_number_)) { - has_log_number_ = true; - } else { - msg = "log number"; - } - break; - - case kPrevLogNumber: - if (GetVarint64(&input, &prev_log_number_)) { - has_prev_log_number_ = true; - } else { - msg = "previous log number"; - } - break; - - case kNextFileNumber: - if (GetVarint64(&input, &next_file_number_)) { - has_next_file_number_ = true; - } else { - msg = "next file number"; - } - break; - - case kLastSequence: - if (GetVarint64(&input, &last_sequence_)) { - has_last_sequence_ = true; - } else { - msg = "last sequence number"; - } - break; - - case kCompactPointer: - if (GetLevel(&input, &level) && - GetInternalKey(&input, &key)) { - compact_pointers_.push_back(std::make_pair(level, key)); - } else { - msg = "compaction pointer"; - } - break; - - case kDeletedFile: - if (GetLevel(&input, &level) && - GetVarint64(&input, &number)) { - deleted_files_.insert(std::make_pair(level, number)); - } else { - msg = "deleted file"; - } - break; - - case kNewFile: - if (GetLevel(&input, &level) && - GetVarint64(&input, &f.number) && - GetVarint64(&input, &f.file_size) && - GetInternalKey(&input, &f.smallest) && - GetInternalKey(&input, &f.largest)) { - new_files_.push_back(std::make_pair(level, f)); - } else { - msg = "new-file entry"; - } - break; - - default: - msg = "unknown tag"; - break; - } - } - - if (msg == NULL && !input.empty()) { - msg = "invalid tag"; - } - - Status result; - if (msg != NULL) { - result = Status::Corruption("VersionEdit", msg); - } - return result; -} - -std::string VersionEdit::DebugString() const { - std::string r; - r.append("VersionEdit {"); - if (has_comparator_) { - r.append("\n Comparator: "); - r.append(comparator_); - } - if (has_log_number_) { - r.append("\n LogNumber: "); - AppendNumberTo(&r, log_number_); - } - if (has_prev_log_number_) { - r.append("\n PrevLogNumber: "); - AppendNumberTo(&r, prev_log_number_); - } - if (has_next_file_number_) { - r.append("\n NextFile: "); - AppendNumberTo(&r, next_file_number_); - } - if (has_last_sequence_) { - r.append("\n LastSeq: "); - AppendNumberTo(&r, last_sequence_); - } - for (size_t i = 0; i < compact_pointers_.size(); i++) { - r.append("\n CompactPointer: "); - AppendNumberTo(&r, compact_pointers_[i].first); - r.append(" "); - r.append(compact_pointers_[i].second.DebugString()); - } - for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); - iter != deleted_files_.end(); - ++iter) { - r.append("\n DeleteFile: "); - AppendNumberTo(&r, iter->first); - r.append(" "); - AppendNumberTo(&r, iter->second); - } - for (size_t i = 0; i < new_files_.size(); i++) { - const FileMetaData& f = new_files_[i].second; - r.append("\n AddFile: "); - AppendNumberTo(&r, new_files_[i].first); - r.append(" "); - AppendNumberTo(&r, f.number); - r.append(" "); - AppendNumberTo(&r, f.file_size); - r.append(" "); - r.append(f.smallest.DebugString()); - r.append(" .. "); - r.append(f.largest.DebugString()); - } - r.append("\n}\n"); - return r; -} - -} // namespace leveldb diff --git a/src/leveldb/db/version_edit.h b/src/leveldb/db/version_edit.h deleted file mode 100644 index eaef77b32..000000000 --- a/src/leveldb/db/version_edit.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_ -#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ - -#include -#include -#include -#include "db/dbformat.h" - -namespace leveldb { - -class VersionSet; - -struct FileMetaData { - int refs; - int allowed_seeks; // Seeks allowed until compaction - uint64_t number; - uint64_t file_size; // File size in bytes - InternalKey smallest; // Smallest internal key served by table - InternalKey largest; // Largest internal key served by table - - FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { } -}; - -class VersionEdit { - public: - VersionEdit() { Clear(); } - ~VersionEdit() { } - - void Clear(); - - void SetComparatorName(const Slice& name) { - has_comparator_ = true; - comparator_ = name.ToString(); - } - void SetLogNumber(uint64_t num) { - has_log_number_ = true; - log_number_ = num; - } - void SetPrevLogNumber(uint64_t num) { - has_prev_log_number_ = true; - prev_log_number_ = num; - } - void SetNextFile(uint64_t num) { - has_next_file_number_ = true; - next_file_number_ = num; - } - void SetLastSequence(SequenceNumber seq) { - has_last_sequence_ = true; - last_sequence_ = seq; - } - void SetCompactPointer(int level, const InternalKey& key) { - compact_pointers_.push_back(std::make_pair(level, key)); - } - - // Add the specified file at the specified number. - // REQUIRES: This version has not been saved (see VersionSet::SaveTo) - // REQUIRES: "smallest" and "largest" are smallest and largest keys in file - void AddFile(int level, uint64_t file, - uint64_t file_size, - const InternalKey& smallest, - const InternalKey& largest) { - FileMetaData f; - f.number = file; - f.file_size = file_size; - f.smallest = smallest; - f.largest = largest; - new_files_.push_back(std::make_pair(level, f)); - } - - // Delete the specified "file" from the specified "level". - void DeleteFile(int level, uint64_t file) { - deleted_files_.insert(std::make_pair(level, file)); - } - - void EncodeTo(std::string* dst) const; - Status DecodeFrom(const Slice& src); - - std::string DebugString() const; - - private: - friend class VersionSet; - - typedef std::set< std::pair > DeletedFileSet; - - std::string comparator_; - uint64_t log_number_; - uint64_t prev_log_number_; - uint64_t next_file_number_; - SequenceNumber last_sequence_; - bool has_comparator_; - bool has_log_number_; - bool has_prev_log_number_; - bool has_next_file_number_; - bool has_last_sequence_; - - std::vector< std::pair > compact_pointers_; - DeletedFileSet deleted_files_; - std::vector< std::pair > new_files_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/src/leveldb/db/version_edit_test.cc b/src/leveldb/db/version_edit_test.cc deleted file mode 100644 index 280310b49..000000000 --- a/src/leveldb/db/version_edit_test.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_edit.h" -#include "util/testharness.h" - -namespace leveldb { - -static void TestEncodeDecode(const VersionEdit& edit) { - std::string encoded, encoded2; - edit.EncodeTo(&encoded); - VersionEdit parsed; - Status s = parsed.DecodeFrom(encoded); - ASSERT_TRUE(s.ok()) << s.ToString(); - parsed.EncodeTo(&encoded2); - ASSERT_EQ(encoded, encoded2); -} - -class VersionEditTest { }; - -TEST(VersionEditTest, EncodeDecode) { - static const uint64_t kBig = 1ull << 50; - - VersionEdit edit; - for (int i = 0; i < 4; i++) { - TestEncodeDecode(edit); - edit.AddFile(3, kBig + 300 + i, kBig + 400 + i, - InternalKey("foo", kBig + 500 + i, kTypeValue), - InternalKey("zoo", kBig + 600 + i, kTypeDeletion)); - edit.DeleteFile(4, kBig + 700 + i); - edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue)); - } - - edit.SetComparatorName("foo"); - edit.SetLogNumber(kBig + 100); - edit.SetNextFile(kBig + 200); - edit.SetLastSequence(kBig + 1000); - TestEncodeDecode(edit); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc deleted file mode 100644 index 7d0a5de2b..000000000 --- a/src/leveldb/db/version_set.cc +++ /dev/null @@ -1,1438 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_set.h" - -#include -#include -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "db/memtable.h" -#include "db/table_cache.h" -#include "leveldb/env.h" -#include "leveldb/table_builder.h" -#include "table/merger.h" -#include "table/two_level_iterator.h" -#include "util/coding.h" -#include "util/logging.h" - -namespace leveldb { - -static const int kTargetFileSize = 2 * 1048576; - -// Maximum bytes of overlaps in grandparent (i.e., level+2) before we -// stop building a single file in a level->level+1 compaction. -static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; - -// Maximum number of bytes in all compacted files. We avoid expanding -// the lower level file set of a compaction if it would make the -// total compaction cover more than this many bytes. -static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; - -static double MaxBytesForLevel(int level) { - // Note: the result for level zero is not really used since we set - // the level-0 compaction threshold based on number of files. - double result = 10 * 1048576.0; // Result for both level-0 and level-1 - while (level > 1) { - result *= 10; - level--; - } - return result; -} - -static uint64_t MaxFileSizeForLevel(int level) { - return kTargetFileSize; // We could vary per level to reduce number of files? -} - -static int64_t TotalFileSize(const std::vector& files) { - int64_t sum = 0; - for (size_t i = 0; i < files.size(); i++) { - sum += files[i]->file_size; - } - return sum; -} - -namespace { -std::string IntSetToString(const std::set& s) { - std::string result = "{"; - for (std::set::const_iterator it = s.begin(); - it != s.end(); - ++it) { - result += (result.size() > 1) ? "," : ""; - result += NumberToString(*it); - } - result += "}"; - return result; -} -} // namespace - -Version::~Version() { - assert(refs_ == 0); - - // Remove from linked list - prev_->next_ = next_; - next_->prev_ = prev_; - - // Drop references to files - for (int level = 0; level < config::kNumLevels; level++) { - for (size_t i = 0; i < files_[level].size(); i++) { - FileMetaData* f = files_[level][i]; - assert(f->refs > 0); - f->refs--; - if (f->refs <= 0) { - delete f; - } - } - } -} - -int FindFile(const InternalKeyComparator& icmp, - const std::vector& files, - const Slice& key) { - uint32_t left = 0; - uint32_t right = files.size(); - while (left < right) { - uint32_t mid = (left + right) / 2; - const FileMetaData* f = files[mid]; - if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { - // Key at "mid.largest" is < "target". Therefore all - // files at or before "mid" are uninteresting. - left = mid + 1; - } else { - // Key at "mid.largest" is >= "target". Therefore all files - // after "mid" are uninteresting. - right = mid; - } - } - return right; -} - -static bool AfterFile(const Comparator* ucmp, - const Slice* user_key, const FileMetaData* f) { - // NULL user_key occurs before all keys and is therefore never after *f - return (user_key != NULL && - ucmp->Compare(*user_key, f->largest.user_key()) > 0); -} - -static bool BeforeFile(const Comparator* ucmp, - const Slice* user_key, const FileMetaData* f) { - // NULL user_key occurs after all keys and is therefore never before *f - return (user_key != NULL && - ucmp->Compare(*user_key, f->smallest.user_key()) < 0); -} - -bool SomeFileOverlapsRange( - const InternalKeyComparator& icmp, - bool disjoint_sorted_files, - const std::vector& files, - const Slice* smallest_user_key, - const Slice* largest_user_key) { - const Comparator* ucmp = icmp.user_comparator(); - if (!disjoint_sorted_files) { - // Need to check against all files - for (size_t i = 0; i < files.size(); i++) { - const FileMetaData* f = files[i]; - if (AfterFile(ucmp, smallest_user_key, f) || - BeforeFile(ucmp, largest_user_key, f)) { - // No overlap - } else { - return true; // Overlap - } - } - return false; - } - - // Binary search over file list - uint32_t index = 0; - if (smallest_user_key != NULL) { - // Find the earliest possible internal key for smallest_user_key - InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); - index = FindFile(icmp, files, small.Encode()); - } - - if (index >= files.size()) { - // beginning of range is after all files, so no overlap. - return false; - } - - return !BeforeFile(ucmp, largest_user_key, files[index]); -} - -// An internal iterator. For a given version/level pair, yields -// information about the files in the level. For a given entry, key() -// is the largest key that occurs in the file, and value() is an -// 16-byte value containing the file number and file size, both -// encoded using EncodeFixed64. -class Version::LevelFileNumIterator : public Iterator { - public: - LevelFileNumIterator(const InternalKeyComparator& icmp, - const std::vector* flist) - : icmp_(icmp), - flist_(flist), - index_(flist->size()) { // Marks as invalid - } - virtual bool Valid() const { - return index_ < flist_->size(); - } - virtual void Seek(const Slice& target) { - index_ = FindFile(icmp_, *flist_, target); - } - virtual void SeekToFirst() { index_ = 0; } - virtual void SeekToLast() { - index_ = flist_->empty() ? 0 : flist_->size() - 1; - } - virtual void Next() { - assert(Valid()); - index_++; - } - virtual void Prev() { - assert(Valid()); - if (index_ == 0) { - index_ = flist_->size(); // Marks as invalid - } else { - index_--; - } - } - Slice key() const { - assert(Valid()); - return (*flist_)[index_]->largest.Encode(); - } - Slice value() const { - assert(Valid()); - EncodeFixed64(value_buf_, (*flist_)[index_]->number); - EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size); - return Slice(value_buf_, sizeof(value_buf_)); - } - virtual Status status() const { return Status::OK(); } - private: - const InternalKeyComparator icmp_; - const std::vector* const flist_; - uint32_t index_; - - // Backing store for value(). Holds the file number and size. - mutable char value_buf_[16]; -}; - -static Iterator* GetFileIterator(void* arg, - const ReadOptions& options, - const Slice& file_value) { - TableCache* cache = reinterpret_cast(arg); - if (file_value.size() != 16) { - return NewErrorIterator( - Status::Corruption("FileReader invoked with unexpected value")); - } else { - return cache->NewIterator(options, - DecodeFixed64(file_value.data()), - DecodeFixed64(file_value.data() + 8)); - } -} - -Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, - int level) const { - return NewTwoLevelIterator( - new LevelFileNumIterator(vset_->icmp_, &files_[level]), - &GetFileIterator, vset_->table_cache_, options); -} - -void Version::AddIterators(const ReadOptions& options, - std::vector* iters) { - // Merge all level zero files together since they may overlap - for (size_t i = 0; i < files_[0].size(); i++) { - iters->push_back( - vset_->table_cache_->NewIterator( - options, files_[0][i]->number, files_[0][i]->file_size)); - } - - // For levels > 0, we can use a concatenating iterator that sequentially - // walks through the non-overlapping files in the level, opening them - // lazily. - for (int level = 1; level < config::kNumLevels; level++) { - if (!files_[level].empty()) { - iters->push_back(NewConcatenatingIterator(options, level)); - } - } -} - -// Callback from TableCache::Get() -namespace { -enum SaverState { - kNotFound, - kFound, - kDeleted, - kCorrupt, -}; -struct Saver { - SaverState state; - const Comparator* ucmp; - Slice user_key; - std::string* value; -}; -} -static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { - Saver* s = reinterpret_cast(arg); - ParsedInternalKey parsed_key; - if (!ParseInternalKey(ikey, &parsed_key)) { - s->state = kCorrupt; - } else { - if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { - s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; - if (s->state == kFound) { - s->value->assign(v.data(), v.size()); - } - } - } -} - -static bool NewestFirst(FileMetaData* a, FileMetaData* b) { - return a->number > b->number; -} - -Status Version::Get(const ReadOptions& options, - const LookupKey& k, - std::string* value, - GetStats* stats) { - Slice ikey = k.internal_key(); - Slice user_key = k.user_key(); - const Comparator* ucmp = vset_->icmp_.user_comparator(); - Status s; - - stats->seek_file = NULL; - stats->seek_file_level = -1; - FileMetaData* last_file_read = NULL; - int last_file_read_level = -1; - - // We can search level-by-level since entries never hop across - // levels. Therefore we are guaranteed that if we find data - // in an smaller level, later levels are irrelevant. - std::vector tmp; - FileMetaData* tmp2; - for (int level = 0; level < config::kNumLevels; level++) { - size_t num_files = files_[level].size(); - if (num_files == 0) continue; - - // Get the list of files to search in this level - FileMetaData* const* files = &files_[level][0]; - if (level == 0) { - // Level-0 files may overlap each other. Find all files that - // overlap user_key and process them in order from newest to oldest. - tmp.reserve(num_files); - for (uint32_t i = 0; i < num_files; i++) { - FileMetaData* f = files[i]; - if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && - ucmp->Compare(user_key, f->largest.user_key()) <= 0) { - tmp.push_back(f); - } - } - if (tmp.empty()) continue; - - std::sort(tmp.begin(), tmp.end(), NewestFirst); - files = &tmp[0]; - num_files = tmp.size(); - } else { - // Binary search to find earliest index whose largest key >= ikey. - uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); - if (index >= num_files) { - files = NULL; - num_files = 0; - } else { - tmp2 = files[index]; - if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { - // All of "tmp2" is past any data for user_key - files = NULL; - num_files = 0; - } else { - files = &tmp2; - num_files = 1; - } - } - } - - for (uint32_t i = 0; i < num_files; ++i) { - if (last_file_read != NULL && stats->seek_file == NULL) { - // We have had more than one seek for this read. Charge the 1st file. - stats->seek_file = last_file_read; - stats->seek_file_level = last_file_read_level; - } - - FileMetaData* f = files[i]; - last_file_read = f; - last_file_read_level = level; - - Saver saver; - saver.state = kNotFound; - saver.ucmp = ucmp; - saver.user_key = user_key; - saver.value = value; - s = vset_->table_cache_->Get(options, f->number, f->file_size, - ikey, &saver, SaveValue); - if (!s.ok()) { - return s; - } - switch (saver.state) { - case kNotFound: - break; // Keep searching in other files - case kFound: - return s; - case kDeleted: - s = Status::NotFound(Slice()); // Use empty error message for speed - return s; - case kCorrupt: - s = Status::Corruption("corrupted key for ", user_key); - return s; - } - } - } - - return Status::NotFound(Slice()); // Use an empty error message for speed -} - -bool Version::UpdateStats(const GetStats& stats) { - FileMetaData* f = stats.seek_file; - if (f != NULL) { - f->allowed_seeks--; - if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) { - file_to_compact_ = f; - file_to_compact_level_ = stats.seek_file_level; - return true; - } - } - return false; -} - -void Version::Ref() { - ++refs_; -} - -void Version::Unref() { - assert(this != &vset_->dummy_versions_); - assert(refs_ >= 1); - --refs_; - if (refs_ == 0) { - delete this; - } -} - -bool Version::OverlapInLevel(int level, - const Slice* smallest_user_key, - const Slice* largest_user_key) { - return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], - smallest_user_key, largest_user_key); -} - -int Version::PickLevelForMemTableOutput( - const Slice& smallest_user_key, - const Slice& largest_user_key) { - int level = 0; - if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { - // Push to next level if there is no overlap in next level, - // and the #bytes overlapping in the level after that are limited. - InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); - InternalKey limit(largest_user_key, 0, static_cast(0)); - std::vector overlaps; - while (level < config::kMaxMemCompactLevel) { - if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { - break; - } - GetOverlappingInputs(level + 2, &start, &limit, &overlaps); - const int64_t sum = TotalFileSize(overlaps); - if (sum > kMaxGrandParentOverlapBytes) { - break; - } - level++; - } - } - return level; -} - -// Store in "*inputs" all files in "level" that overlap [begin,end] -void Version::GetOverlappingInputs( - int level, - const InternalKey* begin, - const InternalKey* end, - std::vector* inputs) { - inputs->clear(); - Slice user_begin, user_end; - if (begin != NULL) { - user_begin = begin->user_key(); - } - if (end != NULL) { - user_end = end->user_key(); - } - const Comparator* user_cmp = vset_->icmp_.user_comparator(); - for (size_t i = 0; i < files_[level].size(); ) { - FileMetaData* f = files_[level][i++]; - const Slice file_start = f->smallest.user_key(); - const Slice file_limit = f->largest.user_key(); - if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) { - // "f" is completely before specified range; skip it - } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) { - // "f" is completely after specified range; skip it - } else { - inputs->push_back(f); - if (level == 0) { - // Level-0 files may overlap each other. So check if the newly - // added file has expanded the range. If so, restart search. - if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) { - user_begin = file_start; - inputs->clear(); - i = 0; - } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) { - user_end = file_limit; - inputs->clear(); - i = 0; - } - } - } - } -} - -std::string Version::DebugString() const { - std::string r; - for (int level = 0; level < config::kNumLevels; level++) { - // E.g., - // --- level 1 --- - // 17:123['a' .. 'd'] - // 20:43['e' .. 'g'] - r.append("--- level "); - AppendNumberTo(&r, level); - r.append(" ---\n"); - const std::vector& files = files_[level]; - for (size_t i = 0; i < files.size(); i++) { - r.push_back(' '); - AppendNumberTo(&r, files[i]->number); - r.push_back(':'); - AppendNumberTo(&r, files[i]->file_size); - r.append("["); - r.append(files[i]->smallest.DebugString()); - r.append(" .. "); - r.append(files[i]->largest.DebugString()); - r.append("]\n"); - } - } - return r; -} - -// A helper class so we can efficiently apply a whole sequence -// of edits to a particular state without creating intermediate -// Versions that contain full copies of the intermediate state. -class VersionSet::Builder { - private: - // Helper to sort by v->files_[file_number].smallest - struct BySmallestKey { - const InternalKeyComparator* internal_comparator; - - bool operator()(FileMetaData* f1, FileMetaData* f2) const { - int r = internal_comparator->Compare(f1->smallest, f2->smallest); - if (r != 0) { - return (r < 0); - } else { - // Break ties by file number - return (f1->number < f2->number); - } - } - }; - - typedef std::set FileSet; - struct LevelState { - std::set deleted_files; - FileSet* added_files; - }; - - VersionSet* vset_; - Version* base_; - LevelState levels_[config::kNumLevels]; - - public: - // Initialize a builder with the files from *base and other info from *vset - Builder(VersionSet* vset, Version* base) - : vset_(vset), - base_(base) { - base_->Ref(); - BySmallestKey cmp; - cmp.internal_comparator = &vset_->icmp_; - for (int level = 0; level < config::kNumLevels; level++) { - levels_[level].added_files = new FileSet(cmp); - } - } - - ~Builder() { - for (int level = 0; level < config::kNumLevels; level++) { - const FileSet* added = levels_[level].added_files; - std::vector to_unref; - to_unref.reserve(added->size()); - for (FileSet::const_iterator it = added->begin(); - it != added->end(); ++it) { - to_unref.push_back(*it); - } - delete added; - for (uint32_t i = 0; i < to_unref.size(); i++) { - FileMetaData* f = to_unref[i]; - f->refs--; - if (f->refs <= 0) { - delete f; - } - } - } - base_->Unref(); - } - - // Apply all of the edits in *edit to the current state. - void Apply(VersionEdit* edit) { - // Update compaction pointers - for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { - const int level = edit->compact_pointers_[i].first; - vset_->compact_pointer_[level] = - edit->compact_pointers_[i].second.Encode().ToString(); - } - - // Delete files - const VersionEdit::DeletedFileSet& del = edit->deleted_files_; - for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); - iter != del.end(); - ++iter) { - const int level = iter->first; - const uint64_t number = iter->second; - levels_[level].deleted_files.insert(number); - } - - // Add new files - for (size_t i = 0; i < edit->new_files_.size(); i++) { - const int level = edit->new_files_[i].first; - FileMetaData* f = new FileMetaData(edit->new_files_[i].second); - f->refs = 1; - - // We arrange to automatically compact this file after - // a certain number of seeks. Let's assume: - // (1) One seek costs 10ms - // (2) Writing or reading 1MB costs 10ms (100MB/s) - // (3) A compaction of 1MB does 25MB of IO: - // 1MB read from this level - // 10-12MB read from next level (boundaries may be misaligned) - // 10-12MB written to next level - // This implies that 25 seeks cost the same as the compaction - // of 1MB of data. I.e., one seek costs approximately the - // same as the compaction of 40KB of data. We are a little - // conservative and allow approximately one seek for every 16KB - // of data before triggering a compaction. - f->allowed_seeks = (f->file_size / 16384); - if (f->allowed_seeks < 100) f->allowed_seeks = 100; - - levels_[level].deleted_files.erase(f->number); - levels_[level].added_files->insert(f); - } - } - - // Save the current state in *v. - void SaveTo(Version* v) { - BySmallestKey cmp; - cmp.internal_comparator = &vset_->icmp_; - for (int level = 0; level < config::kNumLevels; level++) { - // Merge the set of added files with the set of pre-existing files. - // Drop any deleted files. Store the result in *v. - const std::vector& base_files = base_->files_[level]; - std::vector::const_iterator base_iter = base_files.begin(); - std::vector::const_iterator base_end = base_files.end(); - const FileSet* added = levels_[level].added_files; - v->files_[level].reserve(base_files.size() + added->size()); - for (FileSet::const_iterator added_iter = added->begin(); - added_iter != added->end(); - ++added_iter) { - // Add all smaller files listed in base_ - for (std::vector::const_iterator bpos - = std::upper_bound(base_iter, base_end, *added_iter, cmp); - base_iter != bpos; - ++base_iter) { - MaybeAddFile(v, level, *base_iter); - } - - MaybeAddFile(v, level, *added_iter); - } - - // Add remaining base files - for (; base_iter != base_end; ++base_iter) { - MaybeAddFile(v, level, *base_iter); - } - -#ifndef NDEBUG - // Make sure there is no overlap in levels > 0 - if (level > 0) { - for (uint32_t i = 1; i < v->files_[level].size(); i++) { - const InternalKey& prev_end = v->files_[level][i-1]->largest; - const InternalKey& this_begin = v->files_[level][i]->smallest; - if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { - fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", - prev_end.DebugString().c_str(), - this_begin.DebugString().c_str()); - abort(); - } - } - } -#endif - } - } - - void MaybeAddFile(Version* v, int level, FileMetaData* f) { - if (levels_[level].deleted_files.count(f->number) > 0) { - // File is deleted: do nothing - } else { - std::vector* files = &v->files_[level]; - if (level > 0 && !files->empty()) { - // Must not overlap - assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest, - f->smallest) < 0); - } - f->refs++; - files->push_back(f); - } - } -}; - -VersionSet::VersionSet(const std::string& dbname, - const Options* options, - TableCache* table_cache, - const InternalKeyComparator* cmp) - : env_(options->env), - dbname_(dbname), - options_(options), - table_cache_(table_cache), - icmp_(*cmp), - next_file_number_(2), - manifest_file_number_(0), // Filled by Recover() - last_sequence_(0), - log_number_(0), - prev_log_number_(0), - descriptor_file_(NULL), - descriptor_log_(NULL), - dummy_versions_(this), - current_(NULL) { - AppendVersion(new Version(this)); -} - -VersionSet::~VersionSet() { - current_->Unref(); - assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty - delete descriptor_log_; - delete descriptor_file_; -} - -void VersionSet::AppendVersion(Version* v) { - // Make "v" current - assert(v->refs_ == 0); - assert(v != current_); - if (current_ != NULL) { - current_->Unref(); - } - current_ = v; - v->Ref(); - - // Append to linked list - v->prev_ = dummy_versions_.prev_; - v->next_ = &dummy_versions_; - v->prev_->next_ = v; - v->next_->prev_ = v; -} - -Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { - if (edit->has_log_number_) { - assert(edit->log_number_ >= log_number_); - assert(edit->log_number_ < next_file_number_); - } else { - edit->SetLogNumber(log_number_); - } - - if (!edit->has_prev_log_number_) { - edit->SetPrevLogNumber(prev_log_number_); - } - - edit->SetNextFile(next_file_number_); - edit->SetLastSequence(last_sequence_); - - Version* v = new Version(this); - { - Builder builder(this, current_); - builder.Apply(edit); - builder.SaveTo(v); - } - Finalize(v); - - // Initialize new descriptor log file if necessary by creating - // a temporary file that contains a snapshot of the current version. - std::string new_manifest_file; - Status s; - if (descriptor_log_ == NULL) { - // No reason to unlock *mu here since we only hit this path in the - // first call to LogAndApply (when opening the database). - assert(descriptor_file_ == NULL); - new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); - edit->SetNextFile(next_file_number_); - s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); - if (s.ok()) { - descriptor_log_ = new log::Writer(descriptor_file_); - s = WriteSnapshot(descriptor_log_); - } - } - - // Unlock during expensive MANIFEST log write - { - mu->Unlock(); - - // Write new record to MANIFEST log - if (s.ok()) { - std::string record; - edit->EncodeTo(&record); - s = descriptor_log_->AddRecord(record); - if (s.ok()) { - s = descriptor_file_->Sync(); - } - if (!s.ok()) { - Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); - if (ManifestContains(record)) { - Log(options_->info_log, - "MANIFEST contains log record despite error; advancing to new " - "version to prevent mismatch between in-memory and logged state"); - s = Status::OK(); - } - } - } - - // If we just created a new descriptor file, install it by writing a - // new CURRENT file that points to it. - if (s.ok() && !new_manifest_file.empty()) { - s = SetCurrentFile(env_, dbname_, manifest_file_number_); - // No need to double-check MANIFEST in case of error since it - // will be discarded below. - } - - mu->Lock(); - } - - // Install the new version - if (s.ok()) { - AppendVersion(v); - log_number_ = edit->log_number_; - prev_log_number_ = edit->prev_log_number_; - } else { - delete v; - if (!new_manifest_file.empty()) { - delete descriptor_log_; - delete descriptor_file_; - descriptor_log_ = NULL; - descriptor_file_ = NULL; - env_->DeleteFile(new_manifest_file); - } - } - - return s; -} - -Status VersionSet::Recover() { - struct LogReporter : public log::Reader::Reporter { - Status* status; - virtual void Corruption(size_t bytes, const Status& s) { - if (this->status->ok()) *this->status = s; - } - }; - - // Read "CURRENT" file, which contains a pointer to the current manifest file - std::string current; - Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); - if (!s.ok()) { - return s; - } - if (current.empty() || current[current.size()-1] != '\n') { - return Status::Corruption("CURRENT file does not end with newline"); - } - current.resize(current.size() - 1); - - std::string dscname = dbname_ + "/" + current; - SequentialFile* file; - s = env_->NewSequentialFile(dscname, &file); - if (!s.ok()) { - return s; - } - - bool have_log_number = false; - bool have_prev_log_number = false; - bool have_next_file = false; - bool have_last_sequence = false; - uint64_t next_file = 0; - uint64_t last_sequence = 0; - uint64_t log_number = 0; - uint64_t prev_log_number = 0; - Builder builder(this, current_); - - { - LogReporter reporter; - reporter.status = &s; - log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/); - Slice record; - std::string scratch; - while (reader.ReadRecord(&record, &scratch) && s.ok()) { - VersionEdit edit; - s = edit.DecodeFrom(record); - if (s.ok()) { - if (edit.has_comparator_ && - edit.comparator_ != icmp_.user_comparator()->Name()) { - s = Status::InvalidArgument( - edit.comparator_ + " does not match existing comparator ", - icmp_.user_comparator()->Name()); - } - } - - if (s.ok()) { - builder.Apply(&edit); - } - - if (edit.has_log_number_) { - log_number = edit.log_number_; - have_log_number = true; - } - - if (edit.has_prev_log_number_) { - prev_log_number = edit.prev_log_number_; - have_prev_log_number = true; - } - - if (edit.has_next_file_number_) { - next_file = edit.next_file_number_; - have_next_file = true; - } - - if (edit.has_last_sequence_) { - last_sequence = edit.last_sequence_; - have_last_sequence = true; - } - } - } - delete file; - file = NULL; - - if (s.ok()) { - if (!have_next_file) { - s = Status::Corruption("no meta-nextfile entry in descriptor"); - } else if (!have_log_number) { - s = Status::Corruption("no meta-lognumber entry in descriptor"); - } else if (!have_last_sequence) { - s = Status::Corruption("no last-sequence-number entry in descriptor"); - } - - if (!have_prev_log_number) { - prev_log_number = 0; - } - - MarkFileNumberUsed(prev_log_number); - MarkFileNumberUsed(log_number); - } - - if (s.ok()) { - Version* v = new Version(this); - builder.SaveTo(v); - // Install recovered version - Finalize(v); - AppendVersion(v); - manifest_file_number_ = next_file; - next_file_number_ = next_file + 1; - last_sequence_ = last_sequence; - log_number_ = log_number; - prev_log_number_ = prev_log_number; - } - - return s; -} - -void VersionSet::MarkFileNumberUsed(uint64_t number) { - if (next_file_number_ <= number) { - next_file_number_ = number + 1; - } -} - -void VersionSet::Finalize(Version* v) { - // Precomputed best level for next compaction - int best_level = -1; - double best_score = -1; - - for (int level = 0; level < config::kNumLevels-1; level++) { - double score; - if (level == 0) { - // We treat level-0 specially by bounding the number of files - // instead of number of bytes for two reasons: - // - // (1) With larger write-buffer sizes, it is nice not to do too - // many level-0 compactions. - // - // (2) The files in level-0 are merged on every read and - // therefore we wish to avoid too many files when the individual - // file size is small (perhaps because of a small write-buffer - // setting, or very high compression ratios, or lots of - // overwrites/deletions). - score = v->files_[level].size() / - static_cast(config::kL0_CompactionTrigger); - } else { - // Compute the ratio of current size to size limit. - const uint64_t level_bytes = TotalFileSize(v->files_[level]); - score = static_cast(level_bytes) / MaxBytesForLevel(level); - } - - if (score > best_score) { - best_level = level; - best_score = score; - } - } - - v->compaction_level_ = best_level; - v->compaction_score_ = best_score; -} - -Status VersionSet::WriteSnapshot(log::Writer* log) { - // TODO: Break up into multiple records to reduce memory usage on recovery? - - // Save metadata - VersionEdit edit; - edit.SetComparatorName(icmp_.user_comparator()->Name()); - - // Save compaction pointers - for (int level = 0; level < config::kNumLevels; level++) { - if (!compact_pointer_[level].empty()) { - InternalKey key; - key.DecodeFrom(compact_pointer_[level]); - edit.SetCompactPointer(level, key); - } - } - - // Save files - for (int level = 0; level < config::kNumLevels; level++) { - const std::vector& files = current_->files_[level]; - for (size_t i = 0; i < files.size(); i++) { - const FileMetaData* f = files[i]; - edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); - } - } - - std::string record; - edit.EncodeTo(&record); - return log->AddRecord(record); -} - -int VersionSet::NumLevelFiles(int level) const { - assert(level >= 0); - assert(level < config::kNumLevels); - return current_->files_[level].size(); -} - -const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { - // Update code if kNumLevels changes - assert(config::kNumLevels == 7); - snprintf(scratch->buffer, sizeof(scratch->buffer), - "files[ %d %d %d %d %d %d %d ]", - int(current_->files_[0].size()), - int(current_->files_[1].size()), - int(current_->files_[2].size()), - int(current_->files_[3].size()), - int(current_->files_[4].size()), - int(current_->files_[5].size()), - int(current_->files_[6].size())); - return scratch->buffer; -} - -// Return true iff the manifest contains the specified record. -bool VersionSet::ManifestContains(const std::string& record) const { - std::string fname = DescriptorFileName(dbname_, manifest_file_number_); - Log(options_->info_log, "ManifestContains: checking %s\n", fname.c_str()); - SequentialFile* file = NULL; - Status s = env_->NewSequentialFile(fname, &file); - if (!s.ok()) { - Log(options_->info_log, "ManifestContains: %s\n", s.ToString().c_str()); - return false; - } - log::Reader reader(file, NULL, true/*checksum*/, 0); - Slice r; - std::string scratch; - bool result = false; - while (reader.ReadRecord(&r, &scratch)) { - if (r == Slice(record)) { - result = true; - break; - } - } - delete file; - Log(options_->info_log, "ManifestContains: result = %d\n", result ? 1 : 0); - return result; -} - -uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { - uint64_t result = 0; - for (int level = 0; level < config::kNumLevels; level++) { - const std::vector& files = v->files_[level]; - for (size_t i = 0; i < files.size(); i++) { - if (icmp_.Compare(files[i]->largest, ikey) <= 0) { - // Entire file is before "ikey", so just add the file size - result += files[i]->file_size; - } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { - // Entire file is after "ikey", so ignore - if (level > 0) { - // Files other than level 0 are sorted by meta->smallest, so - // no further files in this level will contain data for - // "ikey". - break; - } - } else { - // "ikey" falls in the range for this table. Add the - // approximate offset of "ikey" within the table. - Table* tableptr; - Iterator* iter = table_cache_->NewIterator( - ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); - if (tableptr != NULL) { - result += tableptr->ApproximateOffsetOf(ikey.Encode()); - } - delete iter; - } - } - } - return result; -} - -void VersionSet::AddLiveFiles(std::set* live) { - for (Version* v = dummy_versions_.next_; - v != &dummy_versions_; - v = v->next_) { - for (int level = 0; level < config::kNumLevels; level++) { - const std::vector& files = v->files_[level]; - for (size_t i = 0; i < files.size(); i++) { - live->insert(files[i]->number); - } - } - } -} - -int64_t VersionSet::NumLevelBytes(int level) const { - assert(level >= 0); - assert(level < config::kNumLevels); - return TotalFileSize(current_->files_[level]); -} - -int64_t VersionSet::MaxNextLevelOverlappingBytes() { - int64_t result = 0; - std::vector overlaps; - for (int level = 1; level < config::kNumLevels - 1; level++) { - for (size_t i = 0; i < current_->files_[level].size(); i++) { - const FileMetaData* f = current_->files_[level][i]; - current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest, - &overlaps); - const int64_t sum = TotalFileSize(overlaps); - if (sum > result) { - result = sum; - } - } - } - return result; -} - -// Stores the minimal range that covers all entries in inputs in -// *smallest, *largest. -// REQUIRES: inputs is not empty -void VersionSet::GetRange(const std::vector& inputs, - InternalKey* smallest, - InternalKey* largest) { - assert(!inputs.empty()); - smallest->Clear(); - largest->Clear(); - for (size_t i = 0; i < inputs.size(); i++) { - FileMetaData* f = inputs[i]; - if (i == 0) { - *smallest = f->smallest; - *largest = f->largest; - } else { - if (icmp_.Compare(f->smallest, *smallest) < 0) { - *smallest = f->smallest; - } - if (icmp_.Compare(f->largest, *largest) > 0) { - *largest = f->largest; - } - } - } -} - -// Stores the minimal range that covers all entries in inputs1 and inputs2 -// in *smallest, *largest. -// REQUIRES: inputs is not empty -void VersionSet::GetRange2(const std::vector& inputs1, - const std::vector& inputs2, - InternalKey* smallest, - InternalKey* largest) { - std::vector all = inputs1; - all.insert(all.end(), inputs2.begin(), inputs2.end()); - GetRange(all, smallest, largest); -} - -Iterator* VersionSet::MakeInputIterator(Compaction* c) { - ReadOptions options; - options.verify_checksums = options_->paranoid_checks; - options.fill_cache = false; - - // Level-0 files have to be merged together. For other levels, - // we will make a concatenating iterator per level. - // TODO(opt): use concatenating iterator for level-0 if there is no overlap - const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); - Iterator** list = new Iterator*[space]; - int num = 0; - for (int which = 0; which < 2; which++) { - if (!c->inputs_[which].empty()) { - if (c->level() + which == 0) { - const std::vector& files = c->inputs_[which]; - for (size_t i = 0; i < files.size(); i++) { - list[num++] = table_cache_->NewIterator( - options, files[i]->number, files[i]->file_size); - } - } else { - // Create concatenating iterator for the files from this level - list[num++] = NewTwoLevelIterator( - new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), - &GetFileIterator, table_cache_, options); - } - } - } - assert(num <= space); - Iterator* result = NewMergingIterator(&icmp_, list, num); - delete[] list; - return result; -} - -Compaction* VersionSet::PickCompaction() { - Compaction* c; - int level; - - // We prefer compactions triggered by too much data in a level over - // the compactions triggered by seeks. - const bool size_compaction = (current_->compaction_score_ >= 1); - const bool seek_compaction = (current_->file_to_compact_ != NULL); - if (size_compaction) { - level = current_->compaction_level_; - assert(level >= 0); - assert(level+1 < config::kNumLevels); - c = new Compaction(level); - - // Pick the first file that comes after compact_pointer_[level] - for (size_t i = 0; i < current_->files_[level].size(); i++) { - FileMetaData* f = current_->files_[level][i]; - if (compact_pointer_[level].empty() || - icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { - c->inputs_[0].push_back(f); - break; - } - } - if (c->inputs_[0].empty()) { - // Wrap-around to the beginning of the key space - c->inputs_[0].push_back(current_->files_[level][0]); - } - } else if (seek_compaction) { - level = current_->file_to_compact_level_; - c = new Compaction(level); - c->inputs_[0].push_back(current_->file_to_compact_); - } else { - return NULL; - } - - c->input_version_ = current_; - c->input_version_->Ref(); - - // Files in level 0 may overlap each other, so pick up all overlapping ones - if (level == 0) { - InternalKey smallest, largest; - GetRange(c->inputs_[0], &smallest, &largest); - // Note that the next call will discard the file we placed in - // c->inputs_[0] earlier and replace it with an overlapping set - // which will include the picked file. - current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); - assert(!c->inputs_[0].empty()); - } - - SetupOtherInputs(c); - - return c; -} - -void VersionSet::SetupOtherInputs(Compaction* c) { - const int level = c->level(); - InternalKey smallest, largest; - GetRange(c->inputs_[0], &smallest, &largest); - - current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]); - - // Get entire range covered by compaction - InternalKey all_start, all_limit; - GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); - - // See if we can grow the number of inputs in "level" without - // changing the number of "level+1" files we pick up. - if (!c->inputs_[1].empty()) { - std::vector expanded0; - current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); - const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); - const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); - const int64_t expanded0_size = TotalFileSize(expanded0); - if (expanded0.size() > c->inputs_[0].size() && - inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { - InternalKey new_start, new_limit; - GetRange(expanded0, &new_start, &new_limit); - std::vector expanded1; - current_->GetOverlappingInputs(level+1, &new_start, &new_limit, - &expanded1); - if (expanded1.size() == c->inputs_[1].size()) { - Log(options_->info_log, - "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", - level, - int(c->inputs_[0].size()), - int(c->inputs_[1].size()), - long(inputs0_size), long(inputs1_size), - int(expanded0.size()), - int(expanded1.size()), - long(expanded0_size), long(inputs1_size)); - smallest = new_start; - largest = new_limit; - c->inputs_[0] = expanded0; - c->inputs_[1] = expanded1; - GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); - } - } - } - - // Compute the set of grandparent files that overlap this compaction - // (parent == level+1; grandparent == level+2) - if (level + 2 < config::kNumLevels) { - current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, - &c->grandparents_); - } - - if (false) { - Log(options_->info_log, "Compacting %d '%s' .. '%s'", - level, - smallest.DebugString().c_str(), - largest.DebugString().c_str()); - } - - // Update the place where we will do the next compaction for this level. - // We update this immediately instead of waiting for the VersionEdit - // to be applied so that if the compaction fails, we will try a different - // key range next time. - compact_pointer_[level] = largest.Encode().ToString(); - c->edit_.SetCompactPointer(level, largest); -} - -Compaction* VersionSet::CompactRange( - int level, - const InternalKey* begin, - const InternalKey* end) { - std::vector inputs; - current_->GetOverlappingInputs(level, begin, end, &inputs); - if (inputs.empty()) { - return NULL; - } - - // Avoid compacting too much in one shot in case the range is large. - const uint64_t limit = MaxFileSizeForLevel(level); - uint64_t total = 0; - for (size_t i = 0; i < inputs.size(); i++) { - uint64_t s = inputs[i]->file_size; - total += s; - if (total >= limit) { - inputs.resize(i + 1); - break; - } - } - - Compaction* c = new Compaction(level); - c->input_version_ = current_; - c->input_version_->Ref(); - c->inputs_[0] = inputs; - SetupOtherInputs(c); - return c; -} - -Compaction::Compaction(int level) - : level_(level), - max_output_file_size_(MaxFileSizeForLevel(level)), - input_version_(NULL), - grandparent_index_(0), - seen_key_(false), - overlapped_bytes_(0) { - for (int i = 0; i < config::kNumLevels; i++) { - level_ptrs_[i] = 0; - } -} - -Compaction::~Compaction() { - if (input_version_ != NULL) { - input_version_->Unref(); - } -} - -bool Compaction::IsTrivialMove() const { - // Avoid a move if there is lots of overlapping grandparent data. - // Otherwise, the move could create a parent file that will require - // a very expensive merge later on. - return (num_input_files(0) == 1 && - num_input_files(1) == 0 && - TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); -} - -void Compaction::AddInputDeletions(VersionEdit* edit) { - for (int which = 0; which < 2; which++) { - for (size_t i = 0; i < inputs_[which].size(); i++) { - edit->DeleteFile(level_ + which, inputs_[which][i]->number); - } - } -} - -bool Compaction::IsBaseLevelForKey(const Slice& user_key) { - // Maybe use binary search to find right entry instead of linear search? - const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); - for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { - const std::vector& files = input_version_->files_[lvl]; - for (; level_ptrs_[lvl] < files.size(); ) { - FileMetaData* f = files[level_ptrs_[lvl]]; - if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { - // We've advanced far enough - if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { - // Key falls in this file's range, so definitely not base level - return false; - } - break; - } - level_ptrs_[lvl]++; - } - } - return true; -} - -bool Compaction::ShouldStopBefore(const Slice& internal_key) { - // Scan to find earliest grandparent file that contains key. - const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; - while (grandparent_index_ < grandparents_.size() && - icmp->Compare(internal_key, - grandparents_[grandparent_index_]->largest.Encode()) > 0) { - if (seen_key_) { - overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; - } - grandparent_index_++; - } - seen_key_ = true; - - if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { - // Too much overlap for current output; start new output - overlapped_bytes_ = 0; - return true; - } else { - return false; - } -} - -void Compaction::ReleaseInputs() { - if (input_version_ != NULL) { - input_version_->Unref(); - input_version_ = NULL; - } -} - -} // namespace leveldb diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h deleted file mode 100644 index 9d084fdb7..000000000 --- a/src/leveldb/db/version_set.h +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// The representation of a DBImpl consists of a set of Versions. The -// newest version is called "current". Older versions may be kept -// around to provide a consistent view to live iterators. -// -// Each Version keeps track of a set of Table files per level. The -// entire set of versions is maintained in a VersionSet. -// -// Version,VersionSet are thread-compatible, but require external -// synchronization on all accesses. - -#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ -#define STORAGE_LEVELDB_DB_VERSION_SET_H_ - -#include -#include -#include -#include "db/dbformat.h" -#include "db/version_edit.h" -#include "port/port.h" -#include "port/thread_annotations.h" - -namespace leveldb { - -namespace log { class Writer; } - -class Compaction; -class Iterator; -class MemTable; -class TableBuilder; -class TableCache; -class Version; -class VersionSet; -class WritableFile; - -// Return the smallest index i such that files[i]->largest >= key. -// Return files.size() if there is no such file. -// REQUIRES: "files" contains a sorted list of non-overlapping files. -extern int FindFile(const InternalKeyComparator& icmp, - const std::vector& files, - const Slice& key); - -// Returns true iff some file in "files" overlaps the user key range -// [*smallest,*largest]. -// smallest==NULL represents a key smaller than all keys in the DB. -// largest==NULL represents a key largest than all keys in the DB. -// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges -// in sorted order. -extern bool SomeFileOverlapsRange( - const InternalKeyComparator& icmp, - bool disjoint_sorted_files, - const std::vector& files, - const Slice* smallest_user_key, - const Slice* largest_user_key); - -class Version { - public: - // Append to *iters a sequence of iterators that will - // yield the contents of this Version when merged together. - // REQUIRES: This version has been saved (see VersionSet::SaveTo) - void AddIterators(const ReadOptions&, std::vector* iters); - - // Lookup the value for key. If found, store it in *val and - // return OK. Else return a non-OK status. Fills *stats. - // REQUIRES: lock is not held - struct GetStats { - FileMetaData* seek_file; - int seek_file_level; - }; - Status Get(const ReadOptions&, const LookupKey& key, std::string* val, - GetStats* stats); - - // Adds "stats" into the current state. Returns true if a new - // compaction may need to be triggered, false otherwise. - // REQUIRES: lock is held - bool UpdateStats(const GetStats& stats); - - // Reference count management (so Versions do not disappear out from - // under live iterators) - void Ref(); - void Unref(); - - void GetOverlappingInputs( - int level, - const InternalKey* begin, // NULL means before all keys - const InternalKey* end, // NULL means after all keys - std::vector* inputs); - - // Returns true iff some file in the specified level overlaps - // some part of [*smallest_user_key,*largest_user_key]. - // smallest_user_key==NULL represents a key smaller than all keys in the DB. - // largest_user_key==NULL represents a key largest than all keys in the DB. - bool OverlapInLevel(int level, - const Slice* smallest_user_key, - const Slice* largest_user_key); - - // Return the level at which we should place a new memtable compaction - // result that covers the range [smallest_user_key,largest_user_key]. - int PickLevelForMemTableOutput(const Slice& smallest_user_key, - const Slice& largest_user_key); - - int NumFiles(int level) const { return files_[level].size(); } - - // Return a human readable string that describes this version's contents. - std::string DebugString() const; - - private: - friend class Compaction; - friend class VersionSet; - - class LevelFileNumIterator; - Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; - - VersionSet* vset_; // VersionSet to which this Version belongs - Version* next_; // Next version in linked list - Version* prev_; // Previous version in linked list - int refs_; // Number of live refs to this version - - // List of files per level - std::vector files_[config::kNumLevels]; - - // Next file to compact based on seek stats. - FileMetaData* file_to_compact_; - int file_to_compact_level_; - - // Level that should be compacted next and its compaction score. - // Score < 1 means compaction is not strictly needed. These fields - // are initialized by Finalize(). - double compaction_score_; - int compaction_level_; - - explicit Version(VersionSet* vset) - : vset_(vset), next_(this), prev_(this), refs_(0), - file_to_compact_(NULL), - file_to_compact_level_(-1), - compaction_score_(-1), - compaction_level_(-1) { - } - - ~Version(); - - // No copying allowed - Version(const Version&); - void operator=(const Version&); -}; - -class VersionSet { - public: - VersionSet(const std::string& dbname, - const Options* options, - TableCache* table_cache, - const InternalKeyComparator*); - ~VersionSet(); - - // Apply *edit to the current version to form a new descriptor that - // is both saved to persistent state and installed as the new - // current version. Will release *mu while actually writing to the file. - // REQUIRES: *mu is held on entry. - // REQUIRES: no other thread concurrently calls LogAndApply() - Status LogAndApply(VersionEdit* edit, port::Mutex* mu) - EXCLUSIVE_LOCKS_REQUIRED(mu); - - // Recover the last saved descriptor from persistent storage. - Status Recover(); - - // Return the current version. - Version* current() const { return current_; } - - // Return the current manifest file number - uint64_t ManifestFileNumber() const { return manifest_file_number_; } - - // Allocate and return a new file number - uint64_t NewFileNumber() { return next_file_number_++; } - - // Arrange to reuse "file_number" unless a newer file number has - // already been allocated. - // REQUIRES: "file_number" was returned by a call to NewFileNumber(). - void ReuseFileNumber(uint64_t file_number) { - if (next_file_number_ == file_number + 1) { - next_file_number_ = file_number; - } - } - - // Return the number of Table files at the specified level. - int NumLevelFiles(int level) const; - - // Return the combined file size of all files at the specified level. - int64_t NumLevelBytes(int level) const; - - // Return the last sequence number. - uint64_t LastSequence() const { return last_sequence_; } - - // Set the last sequence number to s. - void SetLastSequence(uint64_t s) { - assert(s >= last_sequence_); - last_sequence_ = s; - } - - // Mark the specified file number as used. - void MarkFileNumberUsed(uint64_t number); - - // Return the current log file number. - uint64_t LogNumber() const { return log_number_; } - - // Return the log file number for the log file that is currently - // being compacted, or zero if there is no such log file. - uint64_t PrevLogNumber() const { return prev_log_number_; } - - // Pick level and inputs for a new compaction. - // Returns NULL if there is no compaction to be done. - // Otherwise returns a pointer to a heap-allocated object that - // describes the compaction. Caller should delete the result. - Compaction* PickCompaction(); - - // Return a compaction object for compacting the range [begin,end] in - // the specified level. Returns NULL if there is nothing in that - // level that overlaps the specified range. Caller should delete - // the result. - Compaction* CompactRange( - int level, - const InternalKey* begin, - const InternalKey* end); - - // Return the maximum overlapping data (in bytes) at next level for any - // file at a level >= 1. - int64_t MaxNextLevelOverlappingBytes(); - - // Create an iterator that reads over the compaction inputs for "*c". - // The caller should delete the iterator when no longer needed. - Iterator* MakeInputIterator(Compaction* c); - - // Returns true iff some level needs a compaction. - bool NeedsCompaction() const { - Version* v = current_; - return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL); - } - - // Add all files listed in any live version to *live. - // May also mutate some internal state. - void AddLiveFiles(std::set* live); - - // Return the approximate offset in the database of the data for - // "key" as of version "v". - uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); - - // Return a human-readable short (single-line) summary of the number - // of files per level. Uses *scratch as backing store. - struct LevelSummaryStorage { - char buffer[100]; - }; - const char* LevelSummary(LevelSummaryStorage* scratch) const; - - private: - class Builder; - - friend class Compaction; - friend class Version; - - void Finalize(Version* v); - - void GetRange(const std::vector& inputs, - InternalKey* smallest, - InternalKey* largest); - - void GetRange2(const std::vector& inputs1, - const std::vector& inputs2, - InternalKey* smallest, - InternalKey* largest); - - void SetupOtherInputs(Compaction* c); - - // Save current contents to *log - Status WriteSnapshot(log::Writer* log); - - void AppendVersion(Version* v); - - bool ManifestContains(const std::string& record) const; - - Env* const env_; - const std::string dbname_; - const Options* const options_; - TableCache* const table_cache_; - const InternalKeyComparator icmp_; - uint64_t next_file_number_; - uint64_t manifest_file_number_; - uint64_t last_sequence_; - uint64_t log_number_; - uint64_t prev_log_number_; // 0 or backing store for memtable being compacted - - // Opened lazily - WritableFile* descriptor_file_; - log::Writer* descriptor_log_; - Version dummy_versions_; // Head of circular doubly-linked list of versions. - Version* current_; // == dummy_versions_.prev_ - - // Per-level key at which the next compaction at that level should start. - // Either an empty string, or a valid InternalKey. - std::string compact_pointer_[config::kNumLevels]; - - // No copying allowed - VersionSet(const VersionSet&); - void operator=(const VersionSet&); -}; - -// A Compaction encapsulates information about a compaction. -class Compaction { - public: - ~Compaction(); - - // Return the level that is being compacted. Inputs from "level" - // and "level+1" will be merged to produce a set of "level+1" files. - int level() const { return level_; } - - // Return the object that holds the edits to the descriptor done - // by this compaction. - VersionEdit* edit() { return &edit_; } - - // "which" must be either 0 or 1 - int num_input_files(int which) const { return inputs_[which].size(); } - - // Return the ith input file at "level()+which" ("which" must be 0 or 1). - FileMetaData* input(int which, int i) const { return inputs_[which][i]; } - - // Maximum size of files to build during this compaction. - uint64_t MaxOutputFileSize() const { return max_output_file_size_; } - - // Is this a trivial compaction that can be implemented by just - // moving a single input file to the next level (no merging or splitting) - bool IsTrivialMove() const; - - // Add all inputs to this compaction as delete operations to *edit. - void AddInputDeletions(VersionEdit* edit); - - // Returns true if the information we have available guarantees that - // the compaction is producing data in "level+1" for which no data exists - // in levels greater than "level+1". - bool IsBaseLevelForKey(const Slice& user_key); - - // Returns true iff we should stop building the current output - // before processing "internal_key". - bool ShouldStopBefore(const Slice& internal_key); - - // Release the input version for the compaction, once the compaction - // is successful. - void ReleaseInputs(); - - private: - friend class Version; - friend class VersionSet; - - explicit Compaction(int level); - - int level_; - uint64_t max_output_file_size_; - Version* input_version_; - VersionEdit edit_; - - // Each compaction reads inputs from "level_" and "level_+1" - std::vector inputs_[2]; // The two sets of inputs - - // State used to check for number of of overlapping grandparent files - // (parent == level_ + 1, grandparent == level_ + 2) - std::vector grandparents_; - size_t grandparent_index_; // Index in grandparent_starts_ - bool seen_key_; // Some output key has been seen - int64_t overlapped_bytes_; // Bytes of overlap between current output - // and grandparent files - - // State for implementing IsBaseLevelForKey - - // level_ptrs_ holds indices into input_version_->levels_: our state - // is that we are positioned at one of the file ranges for each - // higher level than the ones involved in this compaction (i.e. for - // all L >= level_ + 2). - size_t level_ptrs_[config::kNumLevels]; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/src/leveldb/db/version_set_test.cc b/src/leveldb/db/version_set_test.cc deleted file mode 100644 index 501e34d13..000000000 --- a/src/leveldb/db/version_set_test.cc +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_set.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -class FindFileTest { - public: - std::vector files_; - bool disjoint_sorted_files_; - - FindFileTest() : disjoint_sorted_files_(true) { } - - ~FindFileTest() { - for (int i = 0; i < files_.size(); i++) { - delete files_[i]; - } - } - - void Add(const char* smallest, const char* largest, - SequenceNumber smallest_seq = 100, - SequenceNumber largest_seq = 100) { - FileMetaData* f = new FileMetaData; - f->number = files_.size() + 1; - f->smallest = InternalKey(smallest, smallest_seq, kTypeValue); - f->largest = InternalKey(largest, largest_seq, kTypeValue); - files_.push_back(f); - } - - int Find(const char* key) { - InternalKey target(key, 100, kTypeValue); - InternalKeyComparator cmp(BytewiseComparator()); - return FindFile(cmp, files_, target.Encode()); - } - - bool Overlaps(const char* smallest, const char* largest) { - InternalKeyComparator cmp(BytewiseComparator()); - Slice s(smallest != NULL ? smallest : ""); - Slice l(largest != NULL ? largest : ""); - return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_, - (smallest != NULL ? &s : NULL), - (largest != NULL ? &l : NULL)); - } -}; - -TEST(FindFileTest, Empty) { - ASSERT_EQ(0, Find("foo")); - ASSERT_TRUE(! Overlaps("a", "z")); - ASSERT_TRUE(! Overlaps(NULL, "z")); - ASSERT_TRUE(! Overlaps("a", NULL)); - ASSERT_TRUE(! Overlaps(NULL, NULL)); -} - -TEST(FindFileTest, Single) { - Add("p", "q"); - ASSERT_EQ(0, Find("a")); - ASSERT_EQ(0, Find("p")); - ASSERT_EQ(0, Find("p1")); - ASSERT_EQ(0, Find("q")); - ASSERT_EQ(1, Find("q1")); - ASSERT_EQ(1, Find("z")); - - ASSERT_TRUE(! Overlaps("a", "b")); - ASSERT_TRUE(! Overlaps("z1", "z2")); - ASSERT_TRUE(Overlaps("a", "p")); - ASSERT_TRUE(Overlaps("a", "q")); - ASSERT_TRUE(Overlaps("a", "z")); - ASSERT_TRUE(Overlaps("p", "p1")); - ASSERT_TRUE(Overlaps("p", "q")); - ASSERT_TRUE(Overlaps("p", "z")); - ASSERT_TRUE(Overlaps("p1", "p2")); - ASSERT_TRUE(Overlaps("p1", "z")); - ASSERT_TRUE(Overlaps("q", "q")); - ASSERT_TRUE(Overlaps("q", "q1")); - - ASSERT_TRUE(! Overlaps(NULL, "j")); - ASSERT_TRUE(! Overlaps("r", NULL)); - ASSERT_TRUE(Overlaps(NULL, "p")); - ASSERT_TRUE(Overlaps(NULL, "p1")); - ASSERT_TRUE(Overlaps("q", NULL)); - ASSERT_TRUE(Overlaps(NULL, NULL)); -} - - -TEST(FindFileTest, Multiple) { - Add("150", "200"); - Add("200", "250"); - Add("300", "350"); - Add("400", "450"); - ASSERT_EQ(0, Find("100")); - ASSERT_EQ(0, Find("150")); - ASSERT_EQ(0, Find("151")); - ASSERT_EQ(0, Find("199")); - ASSERT_EQ(0, Find("200")); - ASSERT_EQ(1, Find("201")); - ASSERT_EQ(1, Find("249")); - ASSERT_EQ(1, Find("250")); - ASSERT_EQ(2, Find("251")); - ASSERT_EQ(2, Find("299")); - ASSERT_EQ(2, Find("300")); - ASSERT_EQ(2, Find("349")); - ASSERT_EQ(2, Find("350")); - ASSERT_EQ(3, Find("351")); - ASSERT_EQ(3, Find("400")); - ASSERT_EQ(3, Find("450")); - ASSERT_EQ(4, Find("451")); - - ASSERT_TRUE(! Overlaps("100", "149")); - ASSERT_TRUE(! Overlaps("251", "299")); - ASSERT_TRUE(! Overlaps("451", "500")); - ASSERT_TRUE(! Overlaps("351", "399")); - - ASSERT_TRUE(Overlaps("100", "150")); - ASSERT_TRUE(Overlaps("100", "200")); - ASSERT_TRUE(Overlaps("100", "300")); - ASSERT_TRUE(Overlaps("100", "400")); - ASSERT_TRUE(Overlaps("100", "500")); - ASSERT_TRUE(Overlaps("375", "400")); - ASSERT_TRUE(Overlaps("450", "450")); - ASSERT_TRUE(Overlaps("450", "500")); -} - -TEST(FindFileTest, MultipleNullBoundaries) { - Add("150", "200"); - Add("200", "250"); - Add("300", "350"); - Add("400", "450"); - ASSERT_TRUE(! Overlaps(NULL, "149")); - ASSERT_TRUE(! Overlaps("451", NULL)); - ASSERT_TRUE(Overlaps(NULL, NULL)); - ASSERT_TRUE(Overlaps(NULL, "150")); - ASSERT_TRUE(Overlaps(NULL, "199")); - ASSERT_TRUE(Overlaps(NULL, "200")); - ASSERT_TRUE(Overlaps(NULL, "201")); - ASSERT_TRUE(Overlaps(NULL, "400")); - ASSERT_TRUE(Overlaps(NULL, "800")); - ASSERT_TRUE(Overlaps("100", NULL)); - ASSERT_TRUE(Overlaps("200", NULL)); - ASSERT_TRUE(Overlaps("449", NULL)); - ASSERT_TRUE(Overlaps("450", NULL)); -} - -TEST(FindFileTest, OverlapSequenceChecks) { - Add("200", "200", 5000, 3000); - ASSERT_TRUE(! Overlaps("199", "199")); - ASSERT_TRUE(! Overlaps("201", "300")); - ASSERT_TRUE(Overlaps("200", "200")); - ASSERT_TRUE(Overlaps("190", "200")); - ASSERT_TRUE(Overlaps("200", "210")); -} - -TEST(FindFileTest, OverlappingFiles) { - Add("150", "600"); - Add("400", "500"); - disjoint_sorted_files_ = false; - ASSERT_TRUE(! Overlaps("100", "149")); - ASSERT_TRUE(! Overlaps("601", "700")); - ASSERT_TRUE(Overlaps("100", "150")); - ASSERT_TRUE(Overlaps("100", "200")); - ASSERT_TRUE(Overlaps("100", "300")); - ASSERT_TRUE(Overlaps("100", "400")); - ASSERT_TRUE(Overlaps("100", "500")); - ASSERT_TRUE(Overlaps("375", "400")); - ASSERT_TRUE(Overlaps("450", "450")); - ASSERT_TRUE(Overlaps("450", "500")); - ASSERT_TRUE(Overlaps("450", "700")); - ASSERT_TRUE(Overlaps("600", "700")); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/write_batch.cc b/src/leveldb/db/write_batch.cc deleted file mode 100644 index 33f4a4257..000000000 --- a/src/leveldb/db/write_batch.cc +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// WriteBatch::rep_ := -// sequence: fixed64 -// count: fixed32 -// data: record[count] -// record := -// kTypeValue varstring varstring | -// kTypeDeletion varstring -// varstring := -// len: varint32 -// data: uint8[len] - -#include "leveldb/write_batch.h" - -#include "leveldb/db.h" -#include "db/dbformat.h" -#include "db/memtable.h" -#include "db/write_batch_internal.h" -#include "util/coding.h" - -namespace leveldb { - -// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. -static const size_t kHeader = 12; - -WriteBatch::WriteBatch() { - Clear(); -} - -WriteBatch::~WriteBatch() { } - -WriteBatch::Handler::~Handler() { } - -void WriteBatch::Clear() { - rep_.clear(); - rep_.resize(kHeader); -} - -Status WriteBatch::Iterate(Handler* handler) const { - Slice input(rep_); - if (input.size() < kHeader) { - return Status::Corruption("malformed WriteBatch (too small)"); - } - - input.remove_prefix(kHeader); - Slice key, value; - int found = 0; - while (!input.empty()) { - found++; - char tag = input[0]; - input.remove_prefix(1); - switch (tag) { - case kTypeValue: - if (GetLengthPrefixedSlice(&input, &key) && - GetLengthPrefixedSlice(&input, &value)) { - handler->Put(key, value); - } else { - return Status::Corruption("bad WriteBatch Put"); - } - break; - case kTypeDeletion: - if (GetLengthPrefixedSlice(&input, &key)) { - handler->Delete(key); - } else { - return Status::Corruption("bad WriteBatch Delete"); - } - break; - default: - return Status::Corruption("unknown WriteBatch tag"); - } - } - if (found != WriteBatchInternal::Count(this)) { - return Status::Corruption("WriteBatch has wrong count"); - } else { - return Status::OK(); - } -} - -int WriteBatchInternal::Count(const WriteBatch* b) { - return DecodeFixed32(b->rep_.data() + 8); -} - -void WriteBatchInternal::SetCount(WriteBatch* b, int n) { - EncodeFixed32(&b->rep_[8], n); -} - -SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { - return SequenceNumber(DecodeFixed64(b->rep_.data())); -} - -void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { - EncodeFixed64(&b->rep_[0], seq); -} - -void WriteBatch::Put(const Slice& key, const Slice& value) { - WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); - rep_.push_back(static_cast(kTypeValue)); - PutLengthPrefixedSlice(&rep_, key); - PutLengthPrefixedSlice(&rep_, value); -} - -void WriteBatch::Delete(const Slice& key) { - WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); - rep_.push_back(static_cast(kTypeDeletion)); - PutLengthPrefixedSlice(&rep_, key); -} - -namespace { -class MemTableInserter : public WriteBatch::Handler { - public: - SequenceNumber sequence_; - MemTable* mem_; - - virtual void Put(const Slice& key, const Slice& value) { - mem_->Add(sequence_, kTypeValue, key, value); - sequence_++; - } - virtual void Delete(const Slice& key) { - mem_->Add(sequence_, kTypeDeletion, key, Slice()); - sequence_++; - } -}; -} // namespace - -Status WriteBatchInternal::InsertInto(const WriteBatch* b, - MemTable* memtable) { - MemTableInserter inserter; - inserter.sequence_ = WriteBatchInternal::Sequence(b); - inserter.mem_ = memtable; - return b->Iterate(&inserter); -} - -void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { - assert(contents.size() >= kHeader); - b->rep_.assign(contents.data(), contents.size()); -} - -void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { - SetCount(dst, Count(dst) + Count(src)); - assert(src->rep_.size() >= kHeader); - dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); -} - -} // namespace leveldb diff --git a/src/leveldb/db/write_batch_internal.h b/src/leveldb/db/write_batch_internal.h deleted file mode 100644 index 4423a7f31..000000000 --- a/src/leveldb/db/write_batch_internal.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ -#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ - -#include "leveldb/write_batch.h" - -namespace leveldb { - -class MemTable; - -// WriteBatchInternal provides static methods for manipulating a -// WriteBatch that we don't want in the public WriteBatch interface. -class WriteBatchInternal { - public: - // Return the number of entries in the batch. - static int Count(const WriteBatch* batch); - - // Set the count for the number of entries in the batch. - static void SetCount(WriteBatch* batch, int n); - - // Return the seqeunce number for the start of this batch. - static SequenceNumber Sequence(const WriteBatch* batch); - - // Store the specified number as the seqeunce number for the start of - // this batch. - static void SetSequence(WriteBatch* batch, SequenceNumber seq); - - static Slice Contents(const WriteBatch* batch) { - return Slice(batch->rep_); - } - - static size_t ByteSize(const WriteBatch* batch) { - return batch->rep_.size(); - } - - static void SetContents(WriteBatch* batch, const Slice& contents); - - static Status InsertInto(const WriteBatch* batch, MemTable* memtable); - - static void Append(WriteBatch* dst, const WriteBatch* src); -}; - -} // namespace leveldb - - -#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/src/leveldb/db/write_batch_test.cc b/src/leveldb/db/write_batch_test.cc deleted file mode 100644 index 9064e3d85..000000000 --- a/src/leveldb/db/write_batch_test.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" - -#include "db/memtable.h" -#include "db/write_batch_internal.h" -#include "leveldb/env.h" -#include "util/logging.h" -#include "util/testharness.h" - -namespace leveldb { - -static std::string PrintContents(WriteBatch* b) { - InternalKeyComparator cmp(BytewiseComparator()); - MemTable* mem = new MemTable(cmp); - mem->Ref(); - std::string state; - Status s = WriteBatchInternal::InsertInto(b, mem); - int count = 0; - Iterator* iter = mem->NewIterator(); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - ParsedInternalKey ikey; - ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey)); - switch (ikey.type) { - case kTypeValue: - state.append("Put("); - state.append(ikey.user_key.ToString()); - state.append(", "); - state.append(iter->value().ToString()); - state.append(")"); - count++; - break; - case kTypeDeletion: - state.append("Delete("); - state.append(ikey.user_key.ToString()); - state.append(")"); - count++; - break; - } - state.append("@"); - state.append(NumberToString(ikey.sequence)); - } - delete iter; - if (!s.ok()) { - state.append("ParseError()"); - } else if (count != WriteBatchInternal::Count(b)) { - state.append("CountMismatch()"); - } - mem->Unref(); - return state; -} - -class WriteBatchTest { }; - -TEST(WriteBatchTest, Empty) { - WriteBatch batch; - ASSERT_EQ("", PrintContents(&batch)); - ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); -} - -TEST(WriteBatchTest, Multiple) { - WriteBatch batch; - batch.Put(Slice("foo"), Slice("bar")); - batch.Delete(Slice("box")); - batch.Put(Slice("baz"), Slice("boo")); - WriteBatchInternal::SetSequence(&batch, 100); - ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch)); - ASSERT_EQ(3, WriteBatchInternal::Count(&batch)); - ASSERT_EQ("Put(baz, boo)@102" - "Delete(box)@101" - "Put(foo, bar)@100", - PrintContents(&batch)); -} - -TEST(WriteBatchTest, Corruption) { - WriteBatch batch; - batch.Put(Slice("foo"), Slice("bar")); - batch.Delete(Slice("box")); - WriteBatchInternal::SetSequence(&batch, 200); - Slice contents = WriteBatchInternal::Contents(&batch); - WriteBatchInternal::SetContents(&batch, - Slice(contents.data(),contents.size()-1)); - ASSERT_EQ("Put(foo, bar)@200" - "ParseError()", - PrintContents(&batch)); -} - -TEST(WriteBatchTest, Append) { - WriteBatch b1, b2; - WriteBatchInternal::SetSequence(&b1, 200); - WriteBatchInternal::SetSequence(&b2, 300); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("", - PrintContents(&b1)); - b2.Put("a", "va"); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("Put(a, va)@200", - PrintContents(&b1)); - b2.Clear(); - b2.Put("b", "vb"); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("Put(a, va)@200" - "Put(b, vb)@201", - PrintContents(&b1)); - b2.Delete("foo"); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("Put(a, va)@200" - "Put(b, vb)@202" - "Put(b, vb)@201" - "Delete(foo)@203", - PrintContents(&b1)); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/doc/bench/db_bench_sqlite3.cc b/src/leveldb/doc/bench/db_bench_sqlite3.cc deleted file mode 100644 index e63aaa8dc..000000000 --- a/src/leveldb/doc/bench/db_bench_sqlite3.cc +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include -#include "util/histogram.h" -#include "util/random.h" -#include "util/testutil.h" - -// Comma-separated list of operations to run in the specified order -// Actual benchmarks: -// -// fillseq -- write N values in sequential key order in async mode -// fillseqsync -- write N/100 values in sequential key order in sync mode -// fillseqbatch -- batch write N values in sequential key order in async mode -// fillrandom -- write N values in random key order in async mode -// fillrandsync -- write N/100 values in random key order in sync mode -// fillrandbatch -- batch write N values in sequential key order in async mode -// overwrite -- overwrite N values in random key order in async mode -// fillrand100K -- write N/1000 100K values in random order in async mode -// fillseq100K -- write N/1000 100K values in sequential order in async mode -// readseq -- read N times sequentially -// readrandom -- read N times in random order -// readrand100K -- read N/1000 100K values in sequential order in async mode -static const char* FLAGS_benchmarks = - "fillseq," - "fillseqsync," - "fillseqbatch," - "fillrandom," - "fillrandsync," - "fillrandbatch," - "overwrite," - "overwritebatch," - "readrandom," - "readseq," - "fillrand100K," - "fillseq100K," - "readseq," - "readrand100K," - ; - -// Number of key/values to place in database -static int FLAGS_num = 1000000; - -// Number of read operations to do. If negative, do FLAGS_num reads. -static int FLAGS_reads = -1; - -// Size of each value -static int FLAGS_value_size = 100; - -// Print histogram of operation timings -static bool FLAGS_histogram = false; - -// Arrange to generate values that shrink to this fraction of -// their original size after compression -static double FLAGS_compression_ratio = 0.5; - -// Page size. Default 1 KB. -static int FLAGS_page_size = 1024; - -// Number of pages. -// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB. -static int FLAGS_num_pages = 4096; - -// If true, do not destroy the existing database. If you set this -// flag and also specify a benchmark that wants a fresh database, that -// benchmark will fail. -static bool FLAGS_use_existing_db = false; - -// If true, we allow batch writes to occur -static bool FLAGS_transaction = true; - -// If true, we enable Write-Ahead Logging -static bool FLAGS_WAL_enabled = true; - -// Use the db with the following name. -static const char* FLAGS_db = NULL; - -inline -static void ExecErrorCheck(int status, char *err_msg) { - if (status != SQLITE_OK) { - fprintf(stderr, "SQL error: %s\n", err_msg); - sqlite3_free(err_msg); - exit(1); - } -} - -inline -static void StepErrorCheck(int status) { - if (status != SQLITE_DONE) { - fprintf(stderr, "SQL step error: status = %d\n", status); - exit(1); - } -} - -inline -static void ErrorCheck(int status) { - if (status != SQLITE_OK) { - fprintf(stderr, "sqlite3 error: status = %d\n", status); - exit(1); - } -} - -inline -static void WalCheckpoint(sqlite3* db_) { - // Flush all writes to disk - if (FLAGS_WAL_enabled) { - sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL); - } -} - -namespace leveldb { - -// Helper for quickly generating random data. -namespace { -class RandomGenerator { - private: - std::string data_; - int pos_; - - public: - RandomGenerator() { - // We use a limited amount of data over and over again and ensure - // that it is larger than the compression window (32KB), and also - // large enough to serve all typical value sizes we want to write. - Random rnd(301); - std::string piece; - while (data_.size() < 1048576) { - // Add a short fragment that is as compressible as specified - // by FLAGS_compression_ratio. - test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); - data_.append(piece); - } - pos_ = 0; - } - - Slice Generate(int len) { - if (pos_ + len > data_.size()) { - pos_ = 0; - assert(len < data_.size()); - } - pos_ += len; - return Slice(data_.data() + pos_ - len, len); - } -}; - -static Slice TrimSpace(Slice s) { - int start = 0; - while (start < s.size() && isspace(s[start])) { - start++; - } - int limit = s.size(); - while (limit > start && isspace(s[limit-1])) { - limit--; - } - return Slice(s.data() + start, limit - start); -} - -} // namespace - -class Benchmark { - private: - sqlite3* db_; - int db_num_; - int num_; - int reads_; - double start_; - double last_op_finish_; - int64_t bytes_; - std::string message_; - Histogram hist_; - RandomGenerator gen_; - Random rand_; - - // State kept for progress messages - int done_; - int next_report_; // When to report next - - void PrintHeader() { - const int kKeySize = 16; - PrintEnvironment(); - fprintf(stdout, "Keys: %d bytes each\n", kKeySize); - fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size); - fprintf(stdout, "Entries: %d\n", num_); - fprintf(stdout, "RawSize: %.1f MB (estimated)\n", - ((static_cast(kKeySize + FLAGS_value_size) * num_) - / 1048576.0)); - PrintWarnings(); - fprintf(stdout, "------------------------------------------------\n"); - } - - void PrintWarnings() { -#if defined(__GNUC__) && !defined(__OPTIMIZE__) - fprintf(stdout, - "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" - ); -#endif -#ifndef NDEBUG - fprintf(stdout, - "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); -#endif - } - - void PrintEnvironment() { - fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION); - -#if defined(__linux) - time_t now = time(NULL); - fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline - - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if (cpuinfo != NULL) { - char line[1000]; - int num_cpus = 0; - std::string cpu_type; - std::string cache_size; - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - const char* sep = strchr(line, ':'); - if (sep == NULL) { - continue; - } - Slice key = TrimSpace(Slice(line, sep - 1 - line)); - Slice val = TrimSpace(Slice(sep + 1)); - if (key == "model name") { - ++num_cpus; - cpu_type = val.ToString(); - } else if (key == "cache size") { - cache_size = val.ToString(); - } - } - fclose(cpuinfo); - fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); - fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); - } -#endif - } - - void Start() { - start_ = Env::Default()->NowMicros() * 1e-6; - bytes_ = 0; - message_.clear(); - last_op_finish_ = start_; - hist_.Clear(); - done_ = 0; - next_report_ = 100; - } - - void FinishedSingleOp() { - if (FLAGS_histogram) { - double now = Env::Default()->NowMicros() * 1e-6; - double micros = (now - last_op_finish_) * 1e6; - hist_.Add(micros); - if (micros > 20000) { - fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); - fflush(stderr); - } - last_op_finish_ = now; - } - - done_++; - if (done_ >= next_report_) { - if (next_report_ < 1000) next_report_ += 100; - else if (next_report_ < 5000) next_report_ += 500; - else if (next_report_ < 10000) next_report_ += 1000; - else if (next_report_ < 50000) next_report_ += 5000; - else if (next_report_ < 100000) next_report_ += 10000; - else if (next_report_ < 500000) next_report_ += 50000; - else next_report_ += 100000; - fprintf(stderr, "... finished %d ops%30s\r", done_, ""); - fflush(stderr); - } - } - - void Stop(const Slice& name) { - double finish = Env::Default()->NowMicros() * 1e-6; - - // Pretend at least one op was done in case we are running a benchmark - // that does not call FinishedSingleOp(). - if (done_ < 1) done_ = 1; - - if (bytes_ > 0) { - char rate[100]; - snprintf(rate, sizeof(rate), "%6.1f MB/s", - (bytes_ / 1048576.0) / (finish - start_)); - if (!message_.empty()) { - message_ = std::string(rate) + " " + message_; - } else { - message_ = rate; - } - } - - fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", - name.ToString().c_str(), - (finish - start_) * 1e6 / done_, - (message_.empty() ? "" : " "), - message_.c_str()); - if (FLAGS_histogram) { - fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); - } - fflush(stdout); - } - - public: - enum Order { - SEQUENTIAL, - RANDOM - }; - enum DBState { - FRESH, - EXISTING - }; - - Benchmark() - : db_(NULL), - db_num_(0), - num_(FLAGS_num), - reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), - bytes_(0), - rand_(301) { - std::vector files; - std::string test_dir; - Env::Default()->GetTestDirectory(&test_dir); - Env::Default()->GetChildren(test_dir, &files); - if (!FLAGS_use_existing_db) { - for (int i = 0; i < files.size(); i++) { - if (Slice(files[i]).starts_with("dbbench_sqlite3")) { - std::string file_name(test_dir); - file_name += "/"; - file_name += files[i]; - Env::Default()->DeleteFile(file_name.c_str()); - } - } - } - } - - ~Benchmark() { - int status = sqlite3_close(db_); - ErrorCheck(status); - } - - void Run() { - PrintHeader(); - Open(); - - const char* benchmarks = FLAGS_benchmarks; - while (benchmarks != NULL) { - const char* sep = strchr(benchmarks, ','); - Slice name; - if (sep == NULL) { - name = benchmarks; - benchmarks = NULL; - } else { - name = Slice(benchmarks, sep - benchmarks); - benchmarks = sep + 1; - } - - bytes_ = 0; - Start(); - - bool known = true; - bool write_sync = false; - if (name == Slice("fillseq")) { - Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillseqbatch")) { - Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000); - WalCheckpoint(db_); - } else if (name == Slice("fillrandom")) { - Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillrandbatch")) { - Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000); - WalCheckpoint(db_); - } else if (name == Slice("overwrite")) { - Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("overwritebatch")) { - Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000); - WalCheckpoint(db_); - } else if (name == Slice("fillrandsync")) { - write_sync = true; - Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillseqsync")) { - write_sync = true; - Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillrand100K")) { - Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillseq100K")) { - Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); - WalCheckpoint(db_); - } else if (name == Slice("readseq")) { - ReadSequential(); - } else if (name == Slice("readrandom")) { - Read(RANDOM, 1); - } else if (name == Slice("readrand100K")) { - int n = reads_; - reads_ /= 1000; - Read(RANDOM, 1); - reads_ = n; - } else { - known = false; - if (name != Slice()) { // No error message for empty name - fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); - } - } - if (known) { - Stop(name); - } - } - } - - void Open() { - assert(db_ == NULL); - - int status; - char file_name[100]; - char* err_msg = NULL; - db_num_++; - - // Open database - std::string tmp_dir; - Env::Default()->GetTestDirectory(&tmp_dir); - snprintf(file_name, sizeof(file_name), - "%s/dbbench_sqlite3-%d.db", - tmp_dir.c_str(), - db_num_); - status = sqlite3_open(file_name, &db_); - if (status) { - fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_)); - exit(1); - } - - // Change SQLite cache size - char cache_size[100]; - snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d", - FLAGS_num_pages); - status = sqlite3_exec(db_, cache_size, NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - - // FLAGS_page_size is defaulted to 1024 - if (FLAGS_page_size != 1024) { - char page_size[100]; - snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d", - FLAGS_page_size); - status = sqlite3_exec(db_, page_size, NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - } - - // Change journal mode to WAL if WAL enabled flag is on - if (FLAGS_WAL_enabled) { - std::string WAL_stmt = "PRAGMA journal_mode = WAL"; - - // LevelDB's default cache size is a combined 4 MB - std::string WAL_checkpoint = "PRAGMA wal_autocheckpoint = 4096"; - status = sqlite3_exec(db_, WAL_stmt.c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - status = sqlite3_exec(db_, WAL_checkpoint.c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - } - - // Change locking mode to exclusive and create tables/index for database - std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE"; - std::string create_stmt = - "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))"; - std::string stmt_array[] = { locking_stmt, create_stmt }; - int stmt_array_length = sizeof(stmt_array) / sizeof(std::string); - for (int i = 0; i < stmt_array_length; i++) { - status = sqlite3_exec(db_, stmt_array[i].c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - } - } - - void Write(bool write_sync, Order order, DBState state, - int num_entries, int value_size, int entries_per_batch) { - // Create new database if state == FRESH - if (state == FRESH) { - if (FLAGS_use_existing_db) { - message_ = "skipping (--use_existing_db is true)"; - return; - } - sqlite3_close(db_); - db_ = NULL; - Open(); - Start(); - } - - if (num_entries != num_) { - char msg[100]; - snprintf(msg, sizeof(msg), "(%d ops)", num_entries); - message_ = msg; - } - - char* err_msg = NULL; - int status; - - sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt; - std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)"; - std::string begin_trans_str = "BEGIN TRANSACTION;"; - std::string end_trans_str = "END TRANSACTION;"; - - // Check for synchronous flag in options - std::string sync_stmt = (write_sync) ? "PRAGMA synchronous = FULL" : - "PRAGMA synchronous = OFF"; - status = sqlite3_exec(db_, sync_stmt.c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - - // Preparing sqlite3 statements - status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, - &replace_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, - &begin_trans_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, - &end_trans_stmt, NULL); - ErrorCheck(status); - - bool transaction = (entries_per_batch > 1); - for (int i = 0; i < num_entries; i += entries_per_batch) { - // Begin write transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(begin_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(begin_trans_stmt); - ErrorCheck(status); - } - - // Create and execute SQL statements - for (int j = 0; j < entries_per_batch; j++) { - const char* value = gen_.Generate(value_size).data(); - - // Create values for key-value pair - const int k = (order == SEQUENTIAL) ? i + j : - (rand_.Next() % num_entries); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - - // Bind KV values into replace_stmt - status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC); - ErrorCheck(status); - status = sqlite3_bind_blob(replace_stmt, 2, value, - value_size, SQLITE_STATIC); - ErrorCheck(status); - - // Execute replace_stmt - bytes_ += value_size + strlen(key); - status = sqlite3_step(replace_stmt); - StepErrorCheck(status); - - // Reset SQLite statement for another use - status = sqlite3_clear_bindings(replace_stmt); - ErrorCheck(status); - status = sqlite3_reset(replace_stmt); - ErrorCheck(status); - - FinishedSingleOp(); - } - - // End write transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(end_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(end_trans_stmt); - ErrorCheck(status); - } - } - - status = sqlite3_finalize(replace_stmt); - ErrorCheck(status); - status = sqlite3_finalize(begin_trans_stmt); - ErrorCheck(status); - status = sqlite3_finalize(end_trans_stmt); - ErrorCheck(status); - } - - void Read(Order order, int entries_per_batch) { - int status; - sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt; - - std::string read_str = "SELECT * FROM test WHERE key = ?"; - std::string begin_trans_str = "BEGIN TRANSACTION;"; - std::string end_trans_str = "END TRANSACTION;"; - - // Preparing sqlite3 statements - status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, - &begin_trans_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, - &end_trans_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, NULL); - ErrorCheck(status); - - bool transaction = (entries_per_batch > 1); - for (int i = 0; i < reads_; i += entries_per_batch) { - // Begin read transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(begin_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(begin_trans_stmt); - ErrorCheck(status); - } - - // Create and execute SQL statements - for (int j = 0; j < entries_per_batch; j++) { - // Create key value - char key[100]; - int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_); - snprintf(key, sizeof(key), "%016d", k); - - // Bind key value into read_stmt - status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC); - ErrorCheck(status); - - // Execute read statement - while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {} - StepErrorCheck(status); - - // Reset SQLite statement for another use - status = sqlite3_clear_bindings(read_stmt); - ErrorCheck(status); - status = sqlite3_reset(read_stmt); - ErrorCheck(status); - FinishedSingleOp(); - } - - // End read transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(end_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(end_trans_stmt); - ErrorCheck(status); - } - } - - status = sqlite3_finalize(read_stmt); - ErrorCheck(status); - status = sqlite3_finalize(begin_trans_stmt); - ErrorCheck(status); - status = sqlite3_finalize(end_trans_stmt); - ErrorCheck(status); - } - - void ReadSequential() { - int status; - sqlite3_stmt *pStmt; - std::string read_str = "SELECT * FROM test ORDER BY key"; - - status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, NULL); - ErrorCheck(status); - for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) { - bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2); - FinishedSingleOp(); - } - - status = sqlite3_finalize(pStmt); - ErrorCheck(status); - } - -}; - -} // namespace leveldb - -int main(int argc, char** argv) { - std::string default_db_path; - for (int i = 1; i < argc; i++) { - double d; - int n; - char junk; - if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { - FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); - } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_histogram = n; - } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { - FLAGS_compression_ratio = d; - } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_use_existing_db = n; - } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { - FLAGS_num = n; - } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { - FLAGS_reads = n; - } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { - FLAGS_value_size = n; - } else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) { - FLAGS_transaction = false; - } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { - FLAGS_page_size = n; - } else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) { - FLAGS_num_pages = n; - } else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_WAL_enabled = n; - } else if (strncmp(argv[i], "--db=", 5) == 0) { - FLAGS_db = argv[i] + 5; - } else { - fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - exit(1); - } - } - - // Choose a location for the test database if none given with --db= - if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); - default_db_path += "/dbbench"; - FLAGS_db = default_db_path.c_str(); - } - - leveldb::Benchmark benchmark; - benchmark.Run(); - return 0; -} diff --git a/src/leveldb/doc/bench/db_bench_tree_db.cc b/src/leveldb/doc/bench/db_bench_tree_db.cc deleted file mode 100644 index ed86f031c..000000000 --- a/src/leveldb/doc/bench/db_bench_tree_db.cc +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include -#include "util/histogram.h" -#include "util/random.h" -#include "util/testutil.h" - -// Comma-separated list of operations to run in the specified order -// Actual benchmarks: -// -// fillseq -- write N values in sequential key order in async mode -// fillrandom -- write N values in random key order in async mode -// overwrite -- overwrite N values in random key order in async mode -// fillseqsync -- write N/100 values in sequential key order in sync mode -// fillrandsync -- write N/100 values in random key order in sync mode -// fillrand100K -- write N/1000 100K values in random order in async mode -// fillseq100K -- write N/1000 100K values in seq order in async mode -// readseq -- read N times sequentially -// readseq100K -- read N/1000 100K values in sequential order in async mode -// readrand100K -- read N/1000 100K values in sequential order in async mode -// readrandom -- read N times in random order -static const char* FLAGS_benchmarks = - "fillseq," - "fillseqsync," - "fillrandsync," - "fillrandom," - "overwrite," - "readrandom," - "readseq," - "fillrand100K," - "fillseq100K," - "readseq100K," - "readrand100K," - ; - -// Number of key/values to place in database -static int FLAGS_num = 1000000; - -// Number of read operations to do. If negative, do FLAGS_num reads. -static int FLAGS_reads = -1; - -// Size of each value -static int FLAGS_value_size = 100; - -// Arrange to generate values that shrink to this fraction of -// their original size after compression -static double FLAGS_compression_ratio = 0.5; - -// Print histogram of operation timings -static bool FLAGS_histogram = false; - -// Cache size. Default 4 MB -static int FLAGS_cache_size = 4194304; - -// Page size. Default 1 KB -static int FLAGS_page_size = 1024; - -// If true, do not destroy the existing database. If you set this -// flag and also specify a benchmark that wants a fresh database, that -// benchmark will fail. -static bool FLAGS_use_existing_db = false; - -// Compression flag. If true, compression is on. If false, compression -// is off. -static bool FLAGS_compression = true; - -// Use the db with the following name. -static const char* FLAGS_db = NULL; - -inline -static void DBSynchronize(kyotocabinet::TreeDB* db_) -{ - // Synchronize will flush writes to disk - if (!db_->synchronize()) { - fprintf(stderr, "synchronize error: %s\n", db_->error().name()); - } -} - -namespace leveldb { - -// Helper for quickly generating random data. -namespace { -class RandomGenerator { - private: - std::string data_; - int pos_; - - public: - RandomGenerator() { - // We use a limited amount of data over and over again and ensure - // that it is larger than the compression window (32KB), and also - // large enough to serve all typical value sizes we want to write. - Random rnd(301); - std::string piece; - while (data_.size() < 1048576) { - // Add a short fragment that is as compressible as specified - // by FLAGS_compression_ratio. - test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); - data_.append(piece); - } - pos_ = 0; - } - - Slice Generate(int len) { - if (pos_ + len > data_.size()) { - pos_ = 0; - assert(len < data_.size()); - } - pos_ += len; - return Slice(data_.data() + pos_ - len, len); - } -}; - -static Slice TrimSpace(Slice s) { - int start = 0; - while (start < s.size() && isspace(s[start])) { - start++; - } - int limit = s.size(); - while (limit > start && isspace(s[limit-1])) { - limit--; - } - return Slice(s.data() + start, limit - start); -} - -} // namespace - -class Benchmark { - private: - kyotocabinet::TreeDB* db_; - int db_num_; - int num_; - int reads_; - double start_; - double last_op_finish_; - int64_t bytes_; - std::string message_; - Histogram hist_; - RandomGenerator gen_; - Random rand_; - kyotocabinet::LZOCompressor comp_; - - // State kept for progress messages - int done_; - int next_report_; // When to report next - - void PrintHeader() { - const int kKeySize = 16; - PrintEnvironment(); - fprintf(stdout, "Keys: %d bytes each\n", kKeySize); - fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", - FLAGS_value_size, - static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); - fprintf(stdout, "Entries: %d\n", num_); - fprintf(stdout, "RawSize: %.1f MB (estimated)\n", - ((static_cast(kKeySize + FLAGS_value_size) * num_) - / 1048576.0)); - fprintf(stdout, "FileSize: %.1f MB (estimated)\n", - (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) - / 1048576.0)); - PrintWarnings(); - fprintf(stdout, "------------------------------------------------\n"); - } - - void PrintWarnings() { -#if defined(__GNUC__) && !defined(__OPTIMIZE__) - fprintf(stdout, - "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" - ); -#endif -#ifndef NDEBUG - fprintf(stdout, - "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); -#endif - } - - void PrintEnvironment() { - fprintf(stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n", - kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV); - -#if defined(__linux) - time_t now = time(NULL); - fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline - - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if (cpuinfo != NULL) { - char line[1000]; - int num_cpus = 0; - std::string cpu_type; - std::string cache_size; - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - const char* sep = strchr(line, ':'); - if (sep == NULL) { - continue; - } - Slice key = TrimSpace(Slice(line, sep - 1 - line)); - Slice val = TrimSpace(Slice(sep + 1)); - if (key == "model name") { - ++num_cpus; - cpu_type = val.ToString(); - } else if (key == "cache size") { - cache_size = val.ToString(); - } - } - fclose(cpuinfo); - fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); - fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); - } -#endif - } - - void Start() { - start_ = Env::Default()->NowMicros() * 1e-6; - bytes_ = 0; - message_.clear(); - last_op_finish_ = start_; - hist_.Clear(); - done_ = 0; - next_report_ = 100; - } - - void FinishedSingleOp() { - if (FLAGS_histogram) { - double now = Env::Default()->NowMicros() * 1e-6; - double micros = (now - last_op_finish_) * 1e6; - hist_.Add(micros); - if (micros > 20000) { - fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); - fflush(stderr); - } - last_op_finish_ = now; - } - - done_++; - if (done_ >= next_report_) { - if (next_report_ < 1000) next_report_ += 100; - else if (next_report_ < 5000) next_report_ += 500; - else if (next_report_ < 10000) next_report_ += 1000; - else if (next_report_ < 50000) next_report_ += 5000; - else if (next_report_ < 100000) next_report_ += 10000; - else if (next_report_ < 500000) next_report_ += 50000; - else next_report_ += 100000; - fprintf(stderr, "... finished %d ops%30s\r", done_, ""); - fflush(stderr); - } - } - - void Stop(const Slice& name) { - double finish = Env::Default()->NowMicros() * 1e-6; - - // Pretend at least one op was done in case we are running a benchmark - // that does not call FinishedSingleOp(). - if (done_ < 1) done_ = 1; - - if (bytes_ > 0) { - char rate[100]; - snprintf(rate, sizeof(rate), "%6.1f MB/s", - (bytes_ / 1048576.0) / (finish - start_)); - if (!message_.empty()) { - message_ = std::string(rate) + " " + message_; - } else { - message_ = rate; - } - } - - fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", - name.ToString().c_str(), - (finish - start_) * 1e6 / done_, - (message_.empty() ? "" : " "), - message_.c_str()); - if (FLAGS_histogram) { - fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); - } - fflush(stdout); - } - - public: - enum Order { - SEQUENTIAL, - RANDOM - }; - enum DBState { - FRESH, - EXISTING - }; - - Benchmark() - : db_(NULL), - num_(FLAGS_num), - reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), - bytes_(0), - rand_(301) { - std::vector files; - std::string test_dir; - Env::Default()->GetTestDirectory(&test_dir); - Env::Default()->GetChildren(test_dir.c_str(), &files); - if (!FLAGS_use_existing_db) { - for (int i = 0; i < files.size(); i++) { - if (Slice(files[i]).starts_with("dbbench_polyDB")) { - std::string file_name(test_dir); - file_name += "/"; - file_name += files[i]; - Env::Default()->DeleteFile(file_name.c_str()); - } - } - } - } - - ~Benchmark() { - if (!db_->close()) { - fprintf(stderr, "close error: %s\n", db_->error().name()); - } - } - - void Run() { - PrintHeader(); - Open(false); - - const char* benchmarks = FLAGS_benchmarks; - while (benchmarks != NULL) { - const char* sep = strchr(benchmarks, ','); - Slice name; - if (sep == NULL) { - name = benchmarks; - benchmarks = NULL; - } else { - name = Slice(benchmarks, sep - benchmarks); - benchmarks = sep + 1; - } - - Start(); - - bool known = true; - bool write_sync = false; - if (name == Slice("fillseq")) { - Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); - - } else if (name == Slice("fillrandom")) { - Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("overwrite")) { - Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillrandsync")) { - write_sync = true; - Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillseqsync")) { - write_sync = true; - Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillrand100K")) { - Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); - DBSynchronize(db_); - } else if (name == Slice("fillseq100K")) { - Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); - DBSynchronize(db_); - } else if (name == Slice("readseq")) { - ReadSequential(); - } else if (name == Slice("readrandom")) { - ReadRandom(); - } else if (name == Slice("readrand100K")) { - int n = reads_; - reads_ /= 1000; - ReadRandom(); - reads_ = n; - } else if (name == Slice("readseq100K")) { - int n = reads_; - reads_ /= 1000; - ReadSequential(); - reads_ = n; - } else { - known = false; - if (name != Slice()) { // No error message for empty name - fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); - } - } - if (known) { - Stop(name); - } - } - } - - private: - void Open(bool sync) { - assert(db_ == NULL); - - // Initialize db_ - db_ = new kyotocabinet::TreeDB(); - char file_name[100]; - db_num_++; - std::string test_dir; - Env::Default()->GetTestDirectory(&test_dir); - snprintf(file_name, sizeof(file_name), - "%s/dbbench_polyDB-%d.kct", - test_dir.c_str(), - db_num_); - - // Create tuning options and open the database - int open_options = kyotocabinet::PolyDB::OWRITER | - kyotocabinet::PolyDB::OCREATE; - int tune_options = kyotocabinet::TreeDB::TSMALL | - kyotocabinet::TreeDB::TLINEAR; - if (FLAGS_compression) { - tune_options |= kyotocabinet::TreeDB::TCOMPRESS; - db_->tune_compressor(&comp_); - } - db_->tune_options(tune_options); - db_->tune_page_cache(FLAGS_cache_size); - db_->tune_page(FLAGS_page_size); - db_->tune_map(256LL<<20); - if (sync) { - open_options |= kyotocabinet::PolyDB::OAUTOSYNC; - } - if (!db_->open(file_name, open_options)) { - fprintf(stderr, "open error: %s\n", db_->error().name()); - } - } - - void Write(bool sync, Order order, DBState state, - int num_entries, int value_size, int entries_per_batch) { - // Create new database if state == FRESH - if (state == FRESH) { - if (FLAGS_use_existing_db) { - message_ = "skipping (--use_existing_db is true)"; - return; - } - delete db_; - db_ = NULL; - Open(sync); - Start(); // Do not count time taken to destroy/open - } - - if (num_entries != num_) { - char msg[100]; - snprintf(msg, sizeof(msg), "(%d ops)", num_entries); - message_ = msg; - } - - // Write to database - for (int i = 0; i < num_entries; i++) - { - const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - bytes_ += value_size + strlen(key); - std::string cpp_key = key; - if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) { - fprintf(stderr, "set error: %s\n", db_->error().name()); - } - FinishedSingleOp(); - } - } - - void ReadSequential() { - kyotocabinet::DB::Cursor* cur = db_->cursor(); - cur->jump(); - std::string ckey, cvalue; - while (cur->get(&ckey, &cvalue, true)) { - bytes_ += ckey.size() + cvalue.size(); - FinishedSingleOp(); - } - delete cur; - } - - void ReadRandom() { - std::string value; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = rand_.Next() % reads_; - snprintf(key, sizeof(key), "%016d", k); - db_->get(key, &value); - FinishedSingleOp(); - } - } -}; - -} // namespace leveldb - -int main(int argc, char** argv) { - std::string default_db_path; - for (int i = 1; i < argc; i++) { - double d; - int n; - char junk; - if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { - FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); - } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { - FLAGS_compression_ratio = d; - } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_histogram = n; - } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { - FLAGS_num = n; - } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { - FLAGS_reads = n; - } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { - FLAGS_value_size = n; - } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { - FLAGS_cache_size = n; - } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { - FLAGS_page_size = n; - } else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_compression = (n == 1) ? true : false; - } else if (strncmp(argv[i], "--db=", 5) == 0) { - FLAGS_db = argv[i] + 5; - } else { - fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - exit(1); - } - } - - // Choose a location for the test database if none given with --db= - if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); - default_db_path += "/dbbench"; - FLAGS_db = default_db_path.c_str(); - } - - leveldb::Benchmark benchmark; - benchmark.Run(); - return 0; -} diff --git a/src/leveldb/doc/benchmark.html b/src/leveldb/doc/benchmark.html deleted file mode 100644 index c4639772c..000000000 --- a/src/leveldb/doc/benchmark.html +++ /dev/null @@ -1,459 +0,0 @@ - - - -LevelDB Benchmarks - - - - -

LevelDB Benchmarks

-

Google, July 2011

-
- -

In order to test LevelDB's performance, we benchmark it against other well-established database implementations. We compare LevelDB (revision 39) against SQLite3 (version 3.7.6.3) and Kyoto Cabinet's (version 1.2.67) TreeDB (a B+Tree based key-value store). We would like to acknowledge Scott Hess and Mikio Hirabayashi for their suggestions and contributions to the SQLite3 and Kyoto Cabinet benchmarks, respectively.

- -

Benchmarks were all performed on a six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz. (Note that LevelDB uses at most two CPUs since the benchmarks are single threaded: one to run the benchmark, and one for background compactions.) We ran the benchmarks on two machines (with identical processors), one with an Ext3 file system and one with an Ext4 file system. The machine with the Ext3 file system has a SATA Hitachi HDS721050CLA362 hard drive. The machine with the Ext4 file system has a SATA Samsung HD502HJ hard drive. Both hard drives spin at 7200 RPM and have hard drive write-caching enabled (using `hdparm -W 1 [device]`). The numbers reported below are the median of three measurements.

- -

Benchmark Source Code

-

We wrote benchmark tools for SQLite and Kyoto TreeDB based on LevelDB's db_bench. The code for each of the benchmarks resides here:

- - -

Custom Build Specifications

-
    -
  • LevelDB: LevelDB was compiled with the tcmalloc library and the Snappy compression library (revision 33). Assertions were disabled.
  • -
  • TreeDB: TreeDB was compiled using the LZO compression library (version 2.03). Furthermore, we enabled the TSMALL and TLINEAR options when opening the database in order to reduce the footprint of each record.
  • -
  • SQLite: We tuned SQLite's performance, by setting its locking mode to exclusive. We also enabled SQLite's write-ahead logging.
  • -
- -

1. Baseline Performance

-

This section gives the baseline performance of all the -databases. Following sections show how performance changes as various -parameters are varied. For the baseline:

-
    -
  • Each database is allowed 4 MB of cache memory.
  • -
  • Databases are opened in asynchronous write mode. - (LevelDB's sync option, TreeDB's OAUTOSYNC option, and - SQLite3's synchronous options are all turned off). I.e., - every write is pushed to the operating system, but the - benchmark does not wait for the write to reach the disk.
  • -
  • Keys are 16 bytes each.
  • -
  • Value are 100 bytes each (with enough redundancy so that - a simple compressor shrinks them to 50% of their original - size).
  • -
  • Sequential reads/writes traverse the key space in increasing order.
  • -
  • Random reads/writes traverse the key space in random order.
  • -
- -

A. Sequential Reads

- - - - - - - - - - -
LevelDB4,030,000 ops/sec
 
Kyoto TreeDB1,010,000 ops/sec
 
SQLite3383,000 ops/sec
 
-

B. Random Reads

- - - - - - - - - - -
LevelDB129,000 ops/sec
 
Kyoto TreeDB151,000 ops/sec
 
SQLite3134,000 ops/sec
 
-

C. Sequential Writes

- - - - - - - - - - -
LevelDB779,000 ops/sec
 
Kyoto TreeDB342,000 ops/sec
 
SQLite348,600 ops/sec
 
-

D. Random Writes

- - - - - - - - - - -
LevelDB164,000 ops/sec
 
Kyoto TreeDB88,500 ops/sec
 
SQLite39,860 ops/sec
 
- -

LevelDB outperforms both SQLite3 and TreeDB in sequential and random write operations and sequential read operations. Kyoto Cabinet has the fastest random read operations.

- -

2. Write Performance under Different Configurations

-

A. Large Values

-

For this benchmark, we start with an empty database, and write 100,000 byte values (~50% compressible). To keep the benchmark running time reasonable, we stop after writing 1000 values.

-

Sequential Writes

- - - - - - - - - - -
LevelDB1,100 ops/sec
 
Kyoto TreeDB1,000 ops/sec
 
SQLite31,600 ops/sec
 
-

Random Writes

- - - - - - - - - - -
LevelDB480 ops/sec
 
Kyoto TreeDB1,100 ops/sec
 
SQLite31,600 ops/sec
 
-

LevelDB doesn't perform as well with large values of 100,000 bytes each. This is because LevelDB writes keys and values at least twice: first time to the transaction log, and second time (during a compaction) to a sorted file. -With larger values, LevelDB's per-operation efficiency is swamped by the -cost of extra copies of large values.

-

B. Batch Writes

-

A batch write is a set of writes that are applied atomically to the underlying database. A single batch of N writes may be significantly faster than N individual writes. The following benchmark writes one thousand batches where each batch contains one thousand 100-byte values. TreeDB does not support batch writes and is omitted from this benchmark.

-

Sequential Writes

- - - - - - - - - -
LevelDB840,000 entries/sec
 
(1.08x baseline)
SQLite3124,000 entries/sec
 
(2.55x baseline)
-

Random Writes

- - - - - - - - - -
LevelDB221,000 entries/sec
 
(1.35x baseline)
SQLite322,000 entries/sec
 
(2.23x baseline)
- -

Because of the way LevelDB persistent storage is organized, batches of -random writes are not much slower (only a factor of 4x) than batches -of sequential writes.

- -

C. Synchronous Writes

-

In the following benchmark, we enable the synchronous writing modes -of all of the databases. Since this change significantly slows down the -benchmark, we stop after 10,000 writes. For synchronous write tests, we've -disabled hard drive write-caching (using `hdparm -W 0 [device]`).

-
    -
  • For LevelDB, we set WriteOptions.sync = true.
  • -
  • In TreeDB, we enabled TreeDB's OAUTOSYNC option.
  • -
  • For SQLite3, we set "PRAGMA synchronous = FULL".
  • -
-

Sequential Writes

- - - - - - - - - - - - - -
LevelDB100 ops/sec
 
(0.003x baseline)
Kyoto TreeDB7 ops/sec
 
(0.0004x baseline)
SQLite388 ops/sec
 
(0.002x baseline)
-

Random Writes

- - - - - - - - - - - - - -
LevelDB100 ops/sec
 
(0.015x baseline)
Kyoto TreeDB8 ops/sec
 
(0.001x baseline)
SQLite388 ops/sec
 
(0.009x baseline)
- -

Also see the ext4 performance numbers below -since synchronous writes behave significantly differently -on ext3 and ext4.

- -

D. Turning Compression Off

- -

In the baseline measurements, LevelDB and TreeDB were using -light-weight compression -(Snappy for LevelDB, -and LZO for -TreeDB). SQLite3, by default does not use compression. The -experiments below show what happens when compression is disabled in -all of the databases (the SQLite3 numbers are just a copy of -its baseline measurements):

- -

Sequential Writes

- - - - - - - - - - - - - -
LevelDB594,000 ops/sec
 
(0.76x baseline)
Kyoto TreeDB485,000 ops/sec
 
(1.42x baseline)
SQLite348,600 ops/sec
 
(1.00x baseline)
-

Random Writes

- - - - - - - - - - - - - -
LevelDB135,000 ops/sec
 
(0.82x baseline)
Kyoto TreeDB159,000 ops/sec
 
(1.80x baseline)
SQLite39,860 ops/sec
 
(1.00x baseline)
- -

LevelDB's write performance is better with compression than without -since compression decreases the amount of data that has to be written -to disk. Therefore LevelDB users can leave compression enabled in -most scenarios without having worry about a tradeoff between space -usage and performance. TreeDB's performance on the other hand is -better without compression than with compression. Presumably this is -because TreeDB's compression library (LZO) is more expensive than -LevelDB's compression library (Snappy).

- -

E. Using More Memory

-

We increased the overall cache size for each database to 128 MB. For LevelDB, we partitioned 128 MB into a 120 MB write buffer and 8 MB of cache (up from 2 MB of write buffer and 2 MB of cache). For SQLite3, we kept the page size at 1024 bytes, but increased the number of pages to 131,072 (up from 4096). For TreeDB, we also kept the page size at 1024 bytes, but increased the cache size to 128 MB (up from 4 MB).

-

Sequential Writes

- - - - - - - - - - - - - -
LevelDB812,000 ops/sec
 
(1.04x baseline)
Kyoto TreeDB321,000 ops/sec
 
(0.94x baseline)
SQLite348,500 ops/sec
 
(1.00x baseline)
-

Random Writes

- - - - - - - - - - - - - -
LevelDB355,000 ops/sec
 
(2.16x baseline)
Kyoto TreeDB284,000 ops/sec
 
(3.21x baseline)
SQLite39,670 ops/sec
 
(0.98x baseline)
- -

SQLite's performance does not change substantially when compared to -the baseline, but the random write performance for both LevelDB and -TreeDB increases significantly. LevelDB's performance improves -because a larger write buffer reduces the need to merge sorted files -(since it creates a smaller number of larger sorted files). TreeDB's -performance goes up because the entire database is available in memory -for fast in-place updates.

- -

3. Read Performance under Different Configurations

-

A. Larger Caches

-

We increased the overall memory usage to 128 MB for each database. -For LevelDB, we allocated 8 MB to LevelDB's write buffer and 120 MB -to LevelDB's cache. The other databases don't differentiate between a -write buffer and a cache, so we simply set their cache size to 128 -MB.

-

Sequential Reads

- - - - - - - - - - - - - -
LevelDB5,210,000 ops/sec
 
(1.29x baseline)
Kyoto TreeDB1,070,000 ops/sec
 
(1.06x baseline)
SQLite3609,000 ops/sec
 
(1.59x baseline)
- -

Random Reads

- - - - - - - - - - - - - -
LevelDB190,000 ops/sec
 
(1.47x baseline)
Kyoto TreeDB463,000 ops/sec
 
(3.07x baseline)
SQLite3186,000 ops/sec
 
(1.39x baseline)
- -

As expected, the read performance of all of the databases increases -when the caches are enlarged. In particular, TreeDB seems to make -very effective use of a cache that is large enough to hold the entire -database.

- -

B. No Compression Reads

-

For this benchmark, we populated a database with 1 million entries consisting of 16 byte keys and 100 byte values. We compiled LevelDB and Kyoto Cabinet without compression support, so results that are read out from the database are already uncompressed. We've listed the SQLite3 baseline read performance as a point of comparison.

-

Sequential Reads

- - - - - - - - - - - - - -
LevelDB4,880,000 ops/sec
 
(1.21x baseline)
Kyoto TreeDB1,230,000 ops/sec
 
(3.60x baseline)
SQLite3383,000 ops/sec
 
(1.00x baseline)
-

Random Reads

- - - - - - - - - - - - - -
LevelDB149,000 ops/sec
 
(1.16x baseline)
Kyoto TreeDB175,000 ops/sec
 
(1.16x baseline)
SQLite3134,000 ops/sec
 
(1.00x baseline)
- -

Performance of both LevelDB and TreeDB improves a small amount when -compression is disabled. Note however that under different workloads, -performance may very well be better with compression if it allows more -of the working set to fit in memory.

- -

Note about Ext4 Filesystems

-

The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.

- -

Acknowledgements

-

Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.

- - diff --git a/src/leveldb/doc/doc.css b/src/leveldb/doc/doc.css deleted file mode 100644 index 700c564e4..000000000 --- a/src/leveldb/doc/doc.css +++ /dev/null @@ -1,89 +0,0 @@ -body { - margin-left: 0.5in; - margin-right: 0.5in; - background: white; - color: black; -} - -h1 { - margin-left: -0.2in; - font-size: 14pt; -} -h2 { - margin-left: -0in; - font-size: 12pt; -} -h3 { - margin-left: -0in; -} -h4 { - margin-left: -0in; -} -hr { - margin-left: -0in; -} - -/* Definition lists: definition term bold */ -dt { - font-weight: bold; -} - -address { - text-align: center; -} -code,samp,var { - color: blue; -} -kbd { - color: #600000; -} -div.note p { - float: right; - width: 3in; - margin-right: 0%; - padding: 1px; - border: 2px solid #6060a0; - background-color: #fffff0; -} - -ul { - margin-top: -0em; - margin-bottom: -0em; -} - -ol { - margin-top: -0em; - margin-bottom: -0em; -} - -UL.nobullets { - list-style-type: none; - list-style-image: none; - margin-left: -1em; -} - -p { - margin: 1em 0 1em 0; - padding: 0 0 0 0; -} - -pre { - line-height: 1.3em; - padding: 0.4em 0 0.8em 0; - margin: 0 0 0 0; - border: 0 0 0 0; - color: blue; -} - -.datatable { - margin-left: auto; - margin-right: auto; - margin-top: 2em; - margin-bottom: 2em; - border: 1px solid; -} - -.datatable td,th { - padding: 0 0.5em 0 0.5em; - text-align: right; -} diff --git a/src/leveldb/doc/impl.html b/src/leveldb/doc/impl.html deleted file mode 100644 index e870795d2..000000000 --- a/src/leveldb/doc/impl.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - -Leveldb file layout and compactions - - - - -

Files

- -The implementation of leveldb is similar in spirit to the -representation of a single - -Bigtable tablet (section 5.3). -However the organization of the files that make up the representation -is somewhat different and is explained below. - -

-Each database is represented by a set of files stored in a directory. -There are several different types of files as documented below: -

-

Log files

-

-A log file (*.log) stores a sequence of recent updates. Each update -is appended to the current log file. When the log file reaches a -pre-determined size (approximately 4MB by default), it is converted -to a sorted table (see below) and a new log file is created for future -updates. -

-A copy of the current log file is kept in an in-memory structure (the -memtable). This copy is consulted on every read so that read -operations reflect all logged updates. -

-

Sorted tables

-

-A sorted table (*.sst) stores a sequence of entries sorted by key. -Each entry is either a value for the key, or a deletion marker for the -key. (Deletion markers are kept around to hide obsolete values -present in older sorted tables). -

-The set of sorted tables are organized into a sequence of levels. The -sorted table generated from a log file is placed in a special young -level (also called level-0). When the number of young files exceeds a -certain threshold (currently four), all of the young files are merged -together with all of the overlapping level-1 files to produce a -sequence of new level-1 files (we create a new level-1 file for every -2MB of data.) -

-Files in the young level may contain overlapping keys. However files -in other levels have distinct non-overlapping key ranges. Consider -level number L where L >= 1. When the combined size of files in -level-L exceeds (10^L) MB (i.e., 10MB for level-1, 100MB for level-2, -...), one file in level-L, and all of the overlapping files in -level-(L+1) are merged to form a set of new files for level-(L+1). -These merges have the effect of gradually migrating new updates from -the young level to the largest level using only bulk reads and writes -(i.e., minimizing expensive seeks). - -

Manifest

-

-A MANIFEST file lists the set of sorted tables that make up each -level, the corresponding key ranges, and other important metadata. -A new MANIFEST file (with a new number embedded in the file name) -is created whenever the database is reopened. The MANIFEST file is -formatted as a log, and changes made to the serving state (as files -are added or removed) are appended to this log. -

-

Current

-

-CURRENT is a simple text file that contains the name of the latest -MANIFEST file. -

-

Info logs

-

-Informational messages are printed to files named LOG and LOG.old. -

-

Others

-

-Other files used for miscellaneous purposes may also be present -(LOCK, *.dbtmp). - -

Level 0

-When the log file grows above a certain size (1MB by default): -
    -
  • Create a brand new memtable and log file and direct future updates here -
  • In the background: -
      -
    • Write the contents of the previous memtable to an sstable -
    • Discard the memtable -
    • Delete the old log file and the old memtable -
    • Add the new sstable to the young (level-0) level. -
    -
- -

Compactions

- -

-When the size of level L exceeds its limit, we compact it in a -background thread. The compaction picks a file from level L and all -overlapping files from the next level L+1. Note that if a level-L -file overlaps only part of a level-(L+1) file, the entire file at -level-(L+1) is used as an input to the compaction and will be -discarded after the compaction. Aside: because level-0 is special -(files in it may overlap each other), we treat compactions from -level-0 to level-1 specially: a level-0 compaction may pick more than -one level-0 file in case some of these files overlap each other. - -

-A compaction merges the contents of the picked files to produce a -sequence of level-(L+1) files. We switch to producing a new -level-(L+1) file after the current output file has reached the target -file size (2MB). We also switch to a new output file when the key -range of the current output file has grown enough to overlap more then -ten level-(L+2) files. This last rule ensures that a later compaction -of a level-(L+1) file will not pick up too much data from level-(L+2). - -

-The old files are discarded and the new files are added to the serving -state. - -

-Compactions for a particular level rotate through the key space. In -more detail, for each level L, we remember the ending key of the last -compaction at level L. The next compaction for level L will pick the -first file that starts after this key (wrapping around to the -beginning of the key space if there is no such file). - -

-Compactions drop overwritten values. They also drop deletion markers -if there are no higher numbered levels that contain a file whose range -overlaps the current key. - -

Timing

- -Level-0 compactions will read up to four 1MB files from level-0, and -at worst all the level-1 files (10MB). I.e., we will read 14MB and -write 14MB. - -

-Other than the special level-0 compactions, we will pick one 2MB file -from level L. In the worst case, this will overlap ~ 12 files from -level L+1 (10 because level-(L+1) is ten times the size of level-L, -and another two at the boundaries since the file ranges at level-L -will usually not be aligned with the file ranges at level-L+1). The -compaction will therefore read 26MB and write 26MB. Assuming a disk -IO rate of 100MB/s (ballpark range for modern drives), the worst -compaction cost will be approximately 0.5 second. - -

-If we throttle the background writing to something small, say 10% of -the full 100MB/s speed, a compaction may take up to 5 seconds. If the -user is writing at 10MB/s, we might build up lots of level-0 files -(~50 to hold the 5*10MB). This may signficantly increase the cost of -reads due to the overhead of merging more files together on every -read. - -

-Solution 1: To reduce this problem, we might want to increase the log -switching threshold when the number of level-0 files is large. Though -the downside is that the larger this threshold, the more memory we will -need to hold the corresponding memtable. - -

-Solution 2: We might want to decrease write rate artificially when the -number of level-0 files goes up. - -

-Solution 3: We work on reducing the cost of very wide merges. -Perhaps most of the level-0 files will have their blocks sitting -uncompressed in the cache and we will only need to worry about the -O(N) complexity in the merging iterator. - -

Number of files

- -Instead of always making 2MB files, we could make larger files for -larger levels to reduce the total file count, though at the expense of -more bursty compactions. Alternatively, we could shard the set of -files into multiple directories. - -

-An experiment on an ext3 filesystem on Feb 04, 2011 shows -the following timings to do 100K file opens in directories with -varying number of files: - - - - - -
Files in directoryMicroseconds to open a file
10009
1000010
10000016
-So maybe even the sharding is not necessary on modern filesystems? - -

Recovery

- -
    -
  • Read CURRENT to find name of the latest committed MANIFEST -
  • Read the named MANIFEST file -
  • Clean up stale files -
  • We could open all sstables here, but it is probably better to be lazy... -
  • Convert log chunk to a new level-0 sstable -
  • Start directing new writes to a new log file with recovered sequence# -
- -

Garbage collection of files

- -DeleteObsoleteFiles() is called at the end of every -compaction and at the end of recovery. It finds the names of all -files in the database. It deletes all log files that are not the -current log file. It deletes all table files that are not referenced -from some level and are not the output of an active compaction. - - - diff --git a/src/leveldb/doc/index.html b/src/leveldb/doc/index.html deleted file mode 100644 index 3ed0ed9d9..000000000 --- a/src/leveldb/doc/index.html +++ /dev/null @@ -1,549 +0,0 @@ - - - - -Leveldb - - - -

Leveldb

-
Jeff Dean, Sanjay Ghemawat
-

-The leveldb library provides a persistent key value store. Keys and -values are arbitrary byte arrays. The keys are ordered within the key -value store according to a user-specified comparator function. - -

-

Opening A Database

-

-A leveldb database has a name which corresponds to a file system -directory. All of the contents of database are stored in this -directory. The following example shows how to open a database, -creating it if necessary: -

-

-  #include <assert>
-  #include "leveldb/db.h"
-
-  leveldb::DB* db;
-  leveldb::Options options;
-  options.create_if_missing = true;
-  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
-  assert(status.ok());
-  ...
-
-If you want to raise an error if the database already exists, add -the following line before the leveldb::DB::Open call: -
-  options.error_if_exists = true;
-
-

Status

-

-You may have noticed the leveldb::Status type above. Values of this -type are returned by most functions in leveldb that may encounter an -error. You can check if such a result is ok, and also print an -associated error message: -

-

-   leveldb::Status s = ...;
-   if (!s.ok()) cerr << s.ToString() << endl;
-
-

Closing A Database

-

-When you are done with a database, just delete the database object. -Example: -

-

-  ... open the db as described above ...
-  ... do something with db ...
-  delete db;
-
-

Reads And Writes

-

-The database provides Put, Delete, and Get methods to -modify/query the database. For example, the following code -moves the value stored under key1 to key2. -

-  std::string value;
-  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
-  if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
-  if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
-
- -

Atomic Updates

-

-Note that if the process dies after the Put of key2 but before the -delete of key1, the same value may be left stored under multiple keys. -Such problems can be avoided by using the WriteBatch class to -atomically apply a set of updates: -

-

-  #include "leveldb/write_batch.h"
-  ...
-  std::string value;
-  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
-  if (s.ok()) {
-    leveldb::WriteBatch batch;
-    batch.Delete(key1);
-    batch.Put(key2, value);
-    s = db->Write(leveldb::WriteOptions(), &batch);
-  }
-
-The WriteBatch holds a sequence of edits to be made to the database, -and these edits within the batch are applied in order. Note that we -called Delete before Put so that if key1 is identical to key2, -we do not end up erroneously dropping the value entirely. -

-Apart from its atomicity benefits, WriteBatch may also be used to -speed up bulk updates by placing lots of individual mutations into the -same batch. - -

Synchronous Writes

-By default, each write to leveldb is asynchronous: it -returns after pushing the write from the process into the operating -system. The transfer from operating system memory to the underlying -persistent storage happens asynchronously. The sync flag -can be turned on for a particular write to make the write operation -not return until the data being written has been pushed all the way to -persistent storage. (On Posix systems, this is implemented by calling -either fsync(...) or fdatasync(...) or -msync(..., MS_SYNC) before the write operation returns.) -
-  leveldb::WriteOptions write_options;
-  write_options.sync = true;
-  db->Put(write_options, ...);
-
-Asynchronous writes are often more than a thousand times as fast as -synchronous writes. The downside of asynchronous writes is that a -crash of the machine may cause the last few updates to be lost. Note -that a crash of just the writing process (i.e., not a reboot) will not -cause any loss since even when sync is false, an update -is pushed from the process memory into the operating system before it -is considered done. - -

-Asynchronous writes can often be used safely. For example, when -loading a large amount of data into the database you can handle lost -updates by restarting the bulk load after a crash. A hybrid scheme is -also possible where every Nth write is synchronous, and in the event -of a crash, the bulk load is restarted just after the last synchronous -write finished by the previous run. (The synchronous write can update -a marker that describes where to restart on a crash.) - -

-WriteBatch provides an alternative to asynchronous writes. -Multiple updates may be placed in the same WriteBatch and -applied together using a synchronous write (i.e., -write_options.sync is set to true). The extra cost of -the synchronous write will be amortized across all of the writes in -the batch. - -

-

Concurrency

-

-A database may only be opened by one process at a time. -The leveldb implementation acquires a lock from the -operating system to prevent misuse. Within a single process, the -same leveldb::DB object may be safely shared by multiple -concurrent threads. I.e., different threads may write into or fetch -iterators or call Get on the same database without any -external synchronization (the leveldb implementation will -automatically do the required synchronization). However other objects -(like Iterator and WriteBatch) may require external synchronization. -If two threads share such an object, they must protect access to it -using their own locking protocol. More details are available in -the public header files. -

-

Iteration

-

-The following example demonstrates how to print all key,value pairs -in a database. -

-

-  leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
-  for (it->SeekToFirst(); it->Valid(); it->Next()) {
-    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;
-  }
-  assert(it->status().ok());  // Check for any errors found during the scan
-  delete it;
-
-The following variation shows how to process just the keys in the -range [start,limit): -

-

-  for (it->Seek(start);
-       it->Valid() && it->key().ToString() < limit;
-       it->Next()) {
-    ...
-  }
-
-You can also process entries in reverse order. (Caveat: reverse -iteration may be somewhat slower than forward iteration.) -

-

-  for (it->SeekToLast(); it->Valid(); it->Prev()) {
-    ...
-  }
-
-

Snapshots

-

-Snapshots provide consistent read-only views over the entire state of -the key-value store. ReadOptions::snapshot may be non-NULL to indicate -that a read should operate on a particular version of the DB state. -If ReadOptions::snapshot is NULL, the read will operate on an -implicit snapshot of the current state. -

-Snapshots are created by the DB::GetSnapshot() method: -

-

-  leveldb::ReadOptions options;
-  options.snapshot = db->GetSnapshot();
-  ... apply some updates to db ...
-  leveldb::Iterator* iter = db->NewIterator(options);
-  ... read using iter to view the state when the snapshot was created ...
-  delete iter;
-  db->ReleaseSnapshot(options.snapshot);
-
-Note that when a snapshot is no longer needed, it should be released -using the DB::ReleaseSnapshot interface. This allows the -implementation to get rid of state that was being maintained just to -support reading as of that snapshot. -

Slice

-

-The return value of the it->key() and it->value() calls above -are instances of the leveldb::Slice type. Slice is a simple -structure that contains a length and a pointer to an external byte -array. Returning a Slice is a cheaper alternative to returning a -std::string since we do not need to copy potentially large keys and -values. In addition, leveldb methods do not return null-terminated -C-style strings since leveldb keys and values are allowed to -contain '\0' bytes. -

-C++ strings and null-terminated C-style strings can be easily converted -to a Slice: -

-

-   leveldb::Slice s1 = "hello";
-
-   std::string str("world");
-   leveldb::Slice s2 = str;
-
-A Slice can be easily converted back to a C++ string: -
-   std::string str = s1.ToString();
-   assert(str == std::string("hello"));
-
-Be careful when using Slices since it is up to the caller to ensure that -the external byte array into which the Slice points remains live while -the Slice is in use. For example, the following is buggy: -

-

-   leveldb::Slice slice;
-   if (...) {
-     std::string str = ...;
-     slice = str;
-   }
-   Use(slice);
-
-When the if statement goes out of scope, str will be destroyed and the -backing storage for slice will disappear. -

-

Comparators

-

-The preceding examples used the default ordering function for key, -which orders bytes lexicographically. You can however supply a custom -comparator when opening a database. For example, suppose each -database key consists of two numbers and we should sort by the first -number, breaking ties by the second number. First, define a proper -subclass of leveldb::Comparator that expresses these rules: -

-

-  class TwoPartComparator : public leveldb::Comparator {
-   public:
-    // Three-way comparison function:
-    //   if a < b: negative result
-    //   if a > b: positive result
-    //   else: zero result
-    int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
-      int a1, a2, b1, b2;
-      ParseKey(a, &a1, &a2);
-      ParseKey(b, &b1, &b2);
-      if (a1 < b1) return -1;
-      if (a1 > b1) return +1;
-      if (a2 < b2) return -1;
-      if (a2 > b2) return +1;
-      return 0;
-    }
-
-    // Ignore the following methods for now:
-    const char* Name() const { return "TwoPartComparator"; }
-    void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
-    void FindShortSuccessor(std::string*) const { }
-  };
-
-Now create a database using this custom comparator: -

-

-  TwoPartComparator cmp;
-  leveldb::DB* db;
-  leveldb::Options options;
-  options.create_if_missing = true;
-  options.comparator = &cmp;
-  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
-  ...
-
-

Backwards compatibility

-

-The result of the comparator's Name method is attached to the -database when it is created, and is checked on every subsequent -database open. If the name changes, the leveldb::DB::Open call will -fail. Therefore, change the name if and only if the new key format -and comparison function are incompatible with existing databases, and -it is ok to discard the contents of all existing databases. -

-You can however still gradually evolve your key format over time with -a little bit of pre-planning. For example, you could store a version -number at the end of each key (one byte should suffice for most uses). -When you wish to switch to a new key format (e.g., adding an optional -third part to the keys processed by TwoPartComparator), -(a) keep the same comparator name (b) increment the version number -for new keys (c) change the comparator function so it uses the -version numbers found in the keys to decide how to interpret them. -

-

Performance

-

-Performance can be tuned by changing the default values of the -types defined in include/leveldb/options.h. - -

-

Block size

-

-leveldb groups adjacent keys together into the same block and such a -block is the unit of transfer to and from persistent storage. The -default block size is approximately 4096 uncompressed bytes. -Applications that mostly do bulk scans over the contents of the -database may wish to increase this size. Applications that do a lot -of point reads of small values may wish to switch to a smaller block -size if performance measurements indicate an improvement. There isn't -much benefit in using blocks smaller than one kilobyte, or larger than -a few megabytes. Also note that compression will be more effective -with larger block sizes. -

-

Compression

-

-Each block is individually compressed before being written to -persistent storage. Compression is on by default since the default -compression method is very fast, and is automatically disabled for -uncompressible data. In rare cases, applications may want to disable -compression entirely, but should only do so if benchmarks show a -performance improvement: -

-

-  leveldb::Options options;
-  options.compression = leveldb::kNoCompression;
-  ... leveldb::DB::Open(options, name, ...) ....
-
-

Cache

-

-The contents of the database are stored in a set of files in the -filesystem and each file stores a sequence of compressed blocks. If -options.cache is non-NULL, it is used to cache frequently used -uncompressed block contents. -

-

-  #include "leveldb/cache.h"
-
-  leveldb::Options options;
-  options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
-  leveldb::DB* db;
-  leveldb::DB::Open(options, name, &db);
-  ... use the db ...
-  delete db
-  delete options.cache;
-
-Note that the cache holds uncompressed data, and therefore it should -be sized according to application level data sizes, without any -reduction from compression. (Caching of compressed blocks is left to -the operating system buffer cache, or any custom Env -implementation provided by the client.) -

-When performing a bulk read, the application may wish to disable -caching so that the data processed by the bulk read does not end up -displacing most of the cached contents. A per-iterator option can be -used to achieve this: -

-

-  leveldb::ReadOptions options;
-  options.fill_cache = false;
-  leveldb::Iterator* it = db->NewIterator(options);
-  for (it->SeekToFirst(); it->Valid(); it->Next()) {
-    ...
-  }
-
-

Key Layout

-

-Note that the unit of disk transfer and caching is a block. Adjacent -keys (according to the database sort order) will usually be placed in -the same block. Therefore the application can improve its performance -by placing keys that are accessed together near each other and placing -infrequently used keys in a separate region of the key space. -

-For example, suppose we are implementing a simple file system on top -of leveldb. The types of entries we might wish to store are: -

-

-   filename -> permission-bits, length, list of file_block_ids
-   file_block_id -> data
-
-We might want to prefix filename keys with one letter (say '/') and the -file_block_id keys with a different letter (say '0') so that scans -over just the metadata do not force us to fetch and cache bulky file -contents. -

-

Filters

-

-Because of the way leveldb data is organized on disk, -a single Get() call may involve multiple reads from disk. -The optional FilterPolicy mechanism can be used to reduce -the number of disk reads substantially. -

-   leveldb::Options options;
-   options.filter_policy = NewBloomFilterPolicy(10);
-   leveldb::DB* db;
-   leveldb::DB::Open(options, "/tmp/testdb", &db);
-   ... use the database ...
-   delete db;
-   delete options.filter_policy;
-
-The preceding code associates a -Bloom filter -based filtering policy with the database. Bloom filter based -filtering relies on keeping some number of bits of data in memory per -key (in this case 10 bits per key since that is the argument we passed -to NewBloomFilterPolicy). This filter will reduce the number of unnecessary -disk reads needed for Get() calls by a factor of -approximately a 100. Increasing the bits per key will lead to a -larger reduction at the cost of more memory usage. We recommend that -applications whose working set does not fit in memory and that do a -lot of random reads set a filter policy. -

-If you are using a custom comparator, you should ensure that the filter -policy you are using is compatible with your comparator. For example, -consider a comparator that ignores trailing spaces when comparing keys. -NewBloomFilterPolicy must not be used with such a comparator. -Instead, the application should provide a custom filter policy that -also ignores trailing spaces. For example: -

-  class CustomFilterPolicy : public leveldb::FilterPolicy {
-   private:
-    FilterPolicy* builtin_policy_;
-   public:
-    CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) { }
-    ~CustomFilterPolicy() { delete builtin_policy_; }
-
-    const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
-
-    void CreateFilter(const Slice* keys, int n, std::string* dst) const {
-      // Use builtin bloom filter code after removing trailing spaces
-      std::vector<Slice> trimmed(n);
-      for (int i = 0; i < n; i++) {
-        trimmed[i] = RemoveTrailingSpaces(keys[i]);
-      }
-      return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
-    }
-
-    bool KeyMayMatch(const Slice& key, const Slice& filter) const {
-      // Use builtin bloom filter code after removing trailing spaces
-      return builtin_policy_->KeyMayMatch(RemoveTrailingSpaces(key), filter);
-    }
-  };
-
-

-Advanced applications may provide a filter policy that does not use -a bloom filter but uses some other mechanism for summarizing a set -of keys. See leveldb/filter_policy.h for detail. -

-

Checksums

-

-leveldb associates checksums with all data it stores in the file system. -There are two separate controls provided over how aggressively these -checksums are verified: -

-

    -
  • ReadOptions::verify_checksums may be set to true to force - checksum verification of all data that is read from the file system on - behalf of a particular read. By default, no such verification is - done. -

    -

  • Options::paranoid_checks may be set to true before opening a - database to make the database implementation raise an error as soon as - it detects an internal corruption. Depending on which portion of the - database has been corrupted, the error may be raised when the database - is opened, or later by another database operation. By default, - paranoid checking is off so that the database can be used even if - parts of its persistent storage have been corrupted. -

    - If a database is corrupted (perhaps it cannot be opened when - paranoid checking is turned on), the leveldb::RepairDB function - may be used to recover as much of the data as possible -

    -

-

Approximate Sizes

-

-The GetApproximateSizes method can used to get the approximate -number of bytes of file system space used by one or more key ranges. -

-

-   leveldb::Range ranges[2];
-   ranges[0] = leveldb::Range("a", "c");
-   ranges[1] = leveldb::Range("x", "z");
-   uint64_t sizes[2];
-   leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
-
-The preceding call will set sizes[0] to the approximate number of -bytes of file system space used by the key range [a..c) and -sizes[1] to the approximate number of bytes used by the key range -[x..z). -

-

Environment

-

-All file operations (and other operating system calls) issued by the -leveldb implementation are routed through a leveldb::Env object. -Sophisticated clients may wish to provide their own Env -implementation to get better control. For example, an application may -introduce artificial delays in the file IO paths to limit the impact -of leveldb on other activities in the system. -

-

-  class SlowEnv : public leveldb::Env {
-    .. implementation of the Env interface ...
-  };
-
-  SlowEnv env;
-  leveldb::Options options;
-  options.env = &env;
-  Status s = leveldb::DB::Open(options, ...);
-
-

Porting

-

-leveldb may be ported to a new platform by providing platform -specific implementations of the types/methods/functions exported by -leveldb/port/port.h. See leveldb/port/port_example.h for more -details. -

-In addition, the new platform may need a new default leveldb::Env -implementation. See leveldb/util/env_posix.h for an example. - -

Other Information

- -

-Details about the leveldb implementation may be found in -the following documents: -

- - - diff --git a/src/leveldb/doc/log_format.txt b/src/leveldb/doc/log_format.txt deleted file mode 100644 index 5228f624d..000000000 --- a/src/leveldb/doc/log_format.txt +++ /dev/null @@ -1,75 +0,0 @@ -The log file contents are a sequence of 32KB blocks. The only -exception is that the tail of the file may contain a partial block. - -Each block consists of a sequence of records: - block := record* trailer? - record := - checksum: uint32 // crc32c of type and data[] ; little-endian - length: uint16 // little-endian - type: uint8 // One of FULL, FIRST, MIDDLE, LAST - data: uint8[length] - -A record never starts within the last six bytes of a block (since it -won't fit). Any leftover bytes here form the trailer, which must -consist entirely of zero bytes and must be skipped by readers. - -Aside: if exactly seven bytes are left in the current block, and a new -non-zero length record is added, the writer must emit a FIRST record -(which contains zero bytes of user data) to fill up the trailing seven -bytes of the block and then emit all of the user data in subsequent -blocks. - -More types may be added in the future. Some Readers may skip record -types they do not understand, others may report that some data was -skipped. - -FULL == 1 -FIRST == 2 -MIDDLE == 3 -LAST == 4 - -The FULL record contains the contents of an entire user record. - -FIRST, MIDDLE, LAST are types used for user records that have been -split into multiple fragments (typically because of block boundaries). -FIRST is the type of the first fragment of a user record, LAST is the -type of the last fragment of a user record, and MID is the type of all -interior fragments of a user record. - -Example: consider a sequence of user records: - A: length 1000 - B: length 97270 - C: length 8000 -A will be stored as a FULL record in the first block. - -B will be split into three fragments: first fragment occupies the rest -of the first block, second fragment occupies the entirety of the -second block, and the third fragment occupies a prefix of the third -block. This will leave six bytes free in the third block, which will -be left empty as the trailer. - -C will be stored as a FULL record in the fourth block. - -=================== - -Some benefits over the recordio format: - -(1) We do not need any heuristics for resyncing - just go to next -block boundary and scan. If there is a corruption, skip to the next -block. As a side-benefit, we do not get confused when part of the -contents of one log file are embedded as a record inside another log -file. - -(2) Splitting at approximate boundaries (e.g., for mapreduce) is -simple: find the next block boundary and skip records until we -hit a FULL or FIRST record. - -(3) We do not need extra buffering for large records. - -Some downsides compared to recordio format: - -(1) No packing of tiny records. This could be fixed by adding a new -record type, so it is a shortcoming of the current implementation, -not necessarily the format. - -(2) No compression. Again, this could be fixed by adding new record types. diff --git a/src/leveldb/doc/table_format.txt b/src/leveldb/doc/table_format.txt deleted file mode 100644 index ca8f9b446..000000000 --- a/src/leveldb/doc/table_format.txt +++ /dev/null @@ -1,104 +0,0 @@ -File format -=========== - - - [data block 1] - [data block 2] - ... - [data block N] - [meta block 1] - ... - [meta block K] - [metaindex block] - [index block] - [Footer] (fixed size; starts at file_size - sizeof(Footer)) - - -The file contains internal pointers. Each such pointer is called -a BlockHandle and contains the following information: - offset: varint64 - size: varint64 -See https://developers.google.com/protocol-buffers/docs/encoding#varints -for an explanation of varint64 format. - -(1) The sequence of key/value pairs in the file are stored in sorted -order and partitioned into a sequence of data blocks. These blocks -come one after another at the beginning of the file. Each data block -is formatted according to the code in block_builder.cc, and then -optionally compressed. - -(2) After the data blocks we store a bunch of meta blocks. The -supported meta block types are described below. More meta block types -may be added in the future. Each meta block is again formatted using -block_builder.cc and then optionally compressed. - -(3) A "metaindex" block. It contains one entry for every other meta -block where the key is the name of the meta block and the value is a -BlockHandle pointing to that meta block. - -(4) An "index" block. This block contains one entry per data block, -where the key is a string >= last key in that data block and before -the first key in the successive data block. The value is the -BlockHandle for the data block. - -(6) At the very end of the file is a fixed length footer that contains -the BlockHandle of the metaindex and index blocks as well as a magic number. - metaindex_handle: char[p]; // Block handle for metaindex - index_handle: char[q]; // Block handle for index - padding: char[40-p-q]; // zeroed bytes to make fixed length - // (40==2*BlockHandle::kMaxEncodedLength) - magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) - -"filter" Meta Block -------------------- - -If a "FilterPolicy" was specified when the database was opened, a -filter block is stored in each table. The "metaindex" block contains -an entry that maps from "filter." to the BlockHandle for the filter -block where "" is the string returned by the filter policy's -"Name()" method. - -The filter block stores a sequence of filters, where filter i contains -the output of FilterPolicy::CreateFilter() on all keys that are stored -in a block whose file offset falls within the range - - [ i*base ... (i+1)*base-1 ] - -Currently, "base" is 2KB. So for example, if blocks X and Y start in -the range [ 0KB .. 2KB-1 ], all of the keys in X and Y will be -converted to a filter by calling FilterPolicy::CreateFilter(), and the -resulting filter will be stored as the first filter in the filter -block. - -The filter block is formatted as follows: - - [filter 0] - [filter 1] - [filter 2] - ... - [filter N-1] - - [offset of filter 0] : 4 bytes - [offset of filter 1] : 4 bytes - [offset of filter 2] : 4 bytes - ... - [offset of filter N-1] : 4 bytes - - [offset of beginning of offset array] : 4 bytes - lg(base) : 1 byte - -The offset array at the end of the filter block allows efficient -mapping from a data block offset to the corresponding filter. - -"stats" Meta Block ------------------- - -This meta block contains a bunch of stats. The key is the name -of the statistic. The value contains the statistic. -TODO(postrelease): record following stats. - data size - index size - key size (uncompressed) - value size (uncompressed) - number of entries - number of data blocks diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc deleted file mode 100644 index 5879de121..000000000 --- a/src/leveldb/helpers/memenv/memenv.cc +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "helpers/memenv/memenv.h" - -#include "leveldb/env.h" -#include "leveldb/status.h" -#include "port/port.h" -#include "util/mutexlock.h" -#include -#include -#include -#include - -namespace leveldb { - -namespace { - -class FileState { - public: - // FileStates are reference counted. The initial reference count is zero - // and the caller must call Ref() at least once. - FileState() : refs_(0), size_(0) {} - - // Increase the reference count. - void Ref() { - MutexLock lock(&refs_mutex_); - ++refs_; - } - - // Decrease the reference count. Delete if this is the last reference. - void Unref() { - bool do_delete = false; - - { - MutexLock lock(&refs_mutex_); - --refs_; - assert(refs_ >= 0); - if (refs_ <= 0) { - do_delete = true; - } - } - - if (do_delete) { - delete this; - } - } - - uint64_t Size() const { return size_; } - - Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { - if (offset > size_) { - return Status::IOError("Offset greater than file size."); - } - const uint64_t available = size_ - offset; - if (n > available) { - n = available; - } - if (n == 0) { - *result = Slice(); - return Status::OK(); - } - - size_t block = offset / kBlockSize; - size_t block_offset = offset % kBlockSize; - - if (n <= kBlockSize - block_offset) { - // The requested bytes are all in the first block. - *result = Slice(blocks_[block] + block_offset, n); - return Status::OK(); - } - - size_t bytes_to_copy = n; - char* dst = scratch; - - while (bytes_to_copy > 0) { - size_t avail = kBlockSize - block_offset; - if (avail > bytes_to_copy) { - avail = bytes_to_copy; - } - memcpy(dst, blocks_[block] + block_offset, avail); - - bytes_to_copy -= avail; - dst += avail; - block++; - block_offset = 0; - } - - *result = Slice(scratch, n); - return Status::OK(); - } - - Status Append(const Slice& data) { - const char* src = data.data(); - size_t src_len = data.size(); - - while (src_len > 0) { - size_t avail; - size_t offset = size_ % kBlockSize; - - if (offset != 0) { - // There is some room in the last block. - avail = kBlockSize - offset; - } else { - // No room in the last block; push new one. - blocks_.push_back(new char[kBlockSize]); - avail = kBlockSize; - } - - if (avail > src_len) { - avail = src_len; - } - memcpy(blocks_.back() + offset, src, avail); - src_len -= avail; - src += avail; - size_ += avail; - } - - return Status::OK(); - } - - private: - // Private since only Unref() should be used to delete it. - ~FileState() { - for (std::vector::iterator i = blocks_.begin(); i != blocks_.end(); - ++i) { - delete [] *i; - } - } - - // No copying allowed. - FileState(const FileState&); - void operator=(const FileState&); - - port::Mutex refs_mutex_; - int refs_; // Protected by refs_mutex_; - - // The following fields are not protected by any mutex. They are only mutable - // while the file is being written, and concurrent access is not allowed - // to writable files. - std::vector blocks_; - uint64_t size_; - - enum { kBlockSize = 8 * 1024 }; -}; - -class SequentialFileImpl : public SequentialFile { - public: - explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) { - file_->Ref(); - } - - ~SequentialFileImpl() { - file_->Unref(); - } - - virtual Status Read(size_t n, Slice* result, char* scratch) { - Status s = file_->Read(pos_, n, result, scratch); - if (s.ok()) { - pos_ += result->size(); - } - return s; - } - - virtual Status Skip(uint64_t n) { - if (pos_ > file_->Size()) { - return Status::IOError("pos_ > file_->Size()"); - } - const size_t available = file_->Size() - pos_; - if (n > available) { - n = available; - } - pos_ += n; - return Status::OK(); - } - - private: - FileState* file_; - size_t pos_; -}; - -class RandomAccessFileImpl : public RandomAccessFile { - public: - explicit RandomAccessFileImpl(FileState* file) : file_(file) { - file_->Ref(); - } - - ~RandomAccessFileImpl() { - file_->Unref(); - } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - return file_->Read(offset, n, result, scratch); - } - - private: - FileState* file_; -}; - -class WritableFileImpl : public WritableFile { - public: - WritableFileImpl(FileState* file) : file_(file) { - file_->Ref(); - } - - ~WritableFileImpl() { - file_->Unref(); - } - - virtual Status Append(const Slice& data) { - return file_->Append(data); - } - - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - - private: - FileState* file_; -}; - -class NoOpLogger : public Logger { - public: - virtual void Logv(const char* format, va_list ap) { } -}; - -class InMemoryEnv : public EnvWrapper { - public: - explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { } - - virtual ~InMemoryEnv() { - for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ - i->second->Unref(); - } - } - - // Partial implementation of the Env interface. - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - *result = NULL; - return Status::IOError(fname, "File not found"); - } - - *result = new SequentialFileImpl(file_map_[fname]); - return Status::OK(); - } - - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - *result = NULL; - return Status::IOError(fname, "File not found"); - } - - *result = new RandomAccessFileImpl(file_map_[fname]); - return Status::OK(); - } - - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) != file_map_.end()) { - DeleteFileInternal(fname); - } - - FileState* file = new FileState(); - file->Ref(); - file_map_[fname] = file; - - *result = new WritableFileImpl(file); - return Status::OK(); - } - - virtual bool FileExists(const std::string& fname) { - MutexLock lock(&mutex_); - return file_map_.find(fname) != file_map_.end(); - } - - virtual Status GetChildren(const std::string& dir, - std::vector* result) { - MutexLock lock(&mutex_); - result->clear(); - - for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ - const std::string& filename = i->first; - - if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' && - Slice(filename).starts_with(Slice(dir))) { - result->push_back(filename.substr(dir.size() + 1)); - } - } - - return Status::OK(); - } - - void DeleteFileInternal(const std::string& fname) { - if (file_map_.find(fname) == file_map_.end()) { - return; - } - - file_map_[fname]->Unref(); - file_map_.erase(fname); - } - - virtual Status DeleteFile(const std::string& fname) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - return Status::IOError(fname, "File not found"); - } - - DeleteFileInternal(fname); - return Status::OK(); - } - - virtual Status CreateDir(const std::string& dirname) { - return Status::OK(); - } - - virtual Status DeleteDir(const std::string& dirname) { - return Status::OK(); - } - - virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - return Status::IOError(fname, "File not found"); - } - - *file_size = file_map_[fname]->Size(); - return Status::OK(); - } - - virtual Status RenameFile(const std::string& src, - const std::string& target) { - MutexLock lock(&mutex_); - if (file_map_.find(src) == file_map_.end()) { - return Status::IOError(src, "File not found"); - } - - DeleteFileInternal(target); - file_map_[target] = file_map_[src]; - file_map_.erase(src); - return Status::OK(); - } - - virtual Status LockFile(const std::string& fname, FileLock** lock) { - *lock = new FileLock; - return Status::OK(); - } - - virtual Status UnlockFile(FileLock* lock) { - delete lock; - return Status::OK(); - } - - virtual Status GetTestDirectory(std::string* path) { - *path = "/test"; - return Status::OK(); - } - - virtual Status NewLogger(const std::string& fname, Logger** result) { - *result = new NoOpLogger; - return Status::OK(); - } - - private: - // Map from filenames to FileState objects, representing a simple file system. - typedef std::map FileSystem; - port::Mutex mutex_; - FileSystem file_map_; // Protected by mutex_. -}; - -} // namespace - -Env* NewMemEnv(Env* base_env) { - return new InMemoryEnv(base_env); -} - -} // namespace leveldb diff --git a/src/leveldb/helpers/memenv/memenv.h b/src/leveldb/helpers/memenv/memenv.h deleted file mode 100644 index 03b88de76..000000000 --- a/src/leveldb/helpers/memenv/memenv.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ -#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ - -namespace leveldb { - -class Env; - -// Returns a new environment that stores its data in memory and delegates -// all non-file-storage tasks to base_env. The caller must delete the result -// when it is no longer needed. -// *base_env must remain live while the result is in use. -Env* NewMemEnv(Env* base_env); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ diff --git a/src/leveldb/helpers/memenv/memenv_test.cc b/src/leveldb/helpers/memenv/memenv_test.cc deleted file mode 100644 index a44310fed..000000000 --- a/src/leveldb/helpers/memenv/memenv_test.cc +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "helpers/memenv/memenv.h" - -#include "db/db_impl.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "util/testharness.h" -#include -#include - -namespace leveldb { - -class MemEnvTest { - public: - Env* env_; - - MemEnvTest() - : env_(NewMemEnv(Env::Default())) { - } - ~MemEnvTest() { - delete env_; - } -}; - -TEST(MemEnvTest, Basics) { - uint64_t file_size; - WritableFile* writable_file; - std::vector children; - - ASSERT_OK(env_->CreateDir("/dir")); - - // Check that the directory is empty. - ASSERT_TRUE(!env_->FileExists("/dir/non_existent")); - ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok()); - ASSERT_OK(env_->GetChildren("/dir", &children)); - ASSERT_EQ(0, children.size()); - - // Create a file. - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - delete writable_file; - - // Check that the file exists. - ASSERT_TRUE(env_->FileExists("/dir/f")); - ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); - ASSERT_EQ(0, file_size); - ASSERT_OK(env_->GetChildren("/dir", &children)); - ASSERT_EQ(1, children.size()); - ASSERT_EQ("f", children[0]); - - // Write to the file. - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - ASSERT_OK(writable_file->Append("abc")); - delete writable_file; - - // Check for expected size. - ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); - ASSERT_EQ(3, file_size); - - // Check that renaming works. - ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); - ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g")); - ASSERT_TRUE(!env_->FileExists("/dir/f")); - ASSERT_TRUE(env_->FileExists("/dir/g")); - ASSERT_OK(env_->GetFileSize("/dir/g", &file_size)); - ASSERT_EQ(3, file_size); - - // Check that opening non-existent file fails. - SequentialFile* seq_file; - RandomAccessFile* rand_file; - ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok()); - ASSERT_TRUE(!seq_file); - ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok()); - ASSERT_TRUE(!rand_file); - - // Check that deleting works. - ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok()); - ASSERT_OK(env_->DeleteFile("/dir/g")); - ASSERT_TRUE(!env_->FileExists("/dir/g")); - ASSERT_OK(env_->GetChildren("/dir", &children)); - ASSERT_EQ(0, children.size()); - ASSERT_OK(env_->DeleteDir("/dir")); -} - -TEST(MemEnvTest, ReadWrite) { - WritableFile* writable_file; - SequentialFile* seq_file; - RandomAccessFile* rand_file; - Slice result; - char scratch[100]; - - ASSERT_OK(env_->CreateDir("/dir")); - - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - ASSERT_OK(writable_file->Append("hello ")); - ASSERT_OK(writable_file->Append("world")); - delete writable_file; - - // Read sequentially. - ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); - ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello". - ASSERT_EQ(0, result.compare("hello")); - ASSERT_OK(seq_file->Skip(1)); - ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world". - ASSERT_EQ(0, result.compare("world")); - ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF. - ASSERT_EQ(0, result.size()); - ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file. - ASSERT_OK(seq_file->Read(1000, &result, scratch)); - ASSERT_EQ(0, result.size()); - delete seq_file; - - // Random reads. - ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file)); - ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world". - ASSERT_EQ(0, result.compare("world")); - ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello". - ASSERT_EQ(0, result.compare("hello")); - ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d". - ASSERT_EQ(0, result.compare("d")); - - // Too high offset. - ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok()); - delete rand_file; -} - -TEST(MemEnvTest, Locks) { - FileLock* lock; - - // These are no-ops, but we test they return success. - ASSERT_OK(env_->LockFile("some file", &lock)); - ASSERT_OK(env_->UnlockFile(lock)); -} - -TEST(MemEnvTest, Misc) { - std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); - ASSERT_TRUE(!test_dir.empty()); - - WritableFile* writable_file; - ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file)); - - // These are no-ops, but we test they return success. - ASSERT_OK(writable_file->Sync()); - ASSERT_OK(writable_file->Flush()); - ASSERT_OK(writable_file->Close()); - delete writable_file; -} - -TEST(MemEnvTest, LargeWrite) { - const size_t kWriteSize = 300 * 1024; - char* scratch = new char[kWriteSize * 2]; - - std::string write_data; - for (size_t i = 0; i < kWriteSize; ++i) { - write_data.append(1, static_cast(i)); - } - - WritableFile* writable_file; - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - ASSERT_OK(writable_file->Append("foo")); - ASSERT_OK(writable_file->Append(write_data)); - delete writable_file; - - SequentialFile* seq_file; - Slice result; - ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); - ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo". - ASSERT_EQ(0, result.compare("foo")); - - size_t read = 0; - std::string read_data; - while (read < kWriteSize) { - ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch)); - read_data.append(result.data(), result.size()); - read += result.size(); - } - ASSERT_TRUE(write_data == read_data); - delete seq_file; - delete [] scratch; -} - -TEST(MemEnvTest, DBTest) { - Options options; - options.create_if_missing = true; - options.env = env_; - DB* db; - - const Slice keys[] = {Slice("aaa"), Slice("bbb"), Slice("ccc")}; - const Slice vals[] = {Slice("foo"), Slice("bar"), Slice("baz")}; - - ASSERT_OK(DB::Open(options, "/dir/db", &db)); - for (size_t i = 0; i < 3; ++i) { - ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i])); - } - - for (size_t i = 0; i < 3; ++i) { - std::string res; - ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); - ASSERT_TRUE(res == vals[i]); - } - - Iterator* iterator = db->NewIterator(ReadOptions()); - iterator->SeekToFirst(); - for (size_t i = 0; i < 3; ++i) { - ASSERT_TRUE(iterator->Valid()); - ASSERT_TRUE(keys[i] == iterator->key()); - ASSERT_TRUE(vals[i] == iterator->value()); - iterator->Next(); - } - ASSERT_TRUE(!iterator->Valid()); - delete iterator; - - DBImpl* dbi = reinterpret_cast(db); - ASSERT_OK(dbi->TEST_CompactMemTable()); - - for (size_t i = 0; i < 3; ++i) { - std::string res; - ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); - ASSERT_TRUE(res == vals[i]); - } - - delete db; -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/include/leveldb/c.h b/src/leveldb/include/leveldb/c.h deleted file mode 100644 index 1fa58866c..000000000 --- a/src/leveldb/include/leveldb/c.h +++ /dev/null @@ -1,291 +0,0 @@ -/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. See the AUTHORS file for names of contributors. - - C bindings for leveldb. May be useful as a stable ABI that can be - used by programs that keep leveldb in a shared library, or for - a JNI api. - - Does not support: - . getters for the option types - . custom comparators that implement key shortening - . capturing post-write-snapshot - . custom iter, db, env, cache implementations using just the C bindings - - Some conventions: - - (1) We expose just opaque struct pointers and functions to clients. - This allows us to change internal representations without having to - recompile clients. - - (2) For simplicity, there is no equivalent to the Slice type. Instead, - the caller has to pass the pointer and length as separate - arguments. - - (3) Errors are represented by a null-terminated c string. NULL - means no error. All operations that can raise an error are passed - a "char** errptr" as the last argument. One of the following must - be true on entry: - *errptr == NULL - *errptr points to a malloc()ed null-terminated error message - (On Windows, *errptr must have been malloc()-ed by this library.) - On success, a leveldb routine leaves *errptr unchanged. - On failure, leveldb frees the old value of *errptr and - set *errptr to a malloc()ed error message. - - (4) Bools have the type unsigned char (0 == false; rest == true) - - (5) All of the pointer arguments must be non-NULL. -*/ - -#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ -#define STORAGE_LEVELDB_INCLUDE_C_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/* Exported types */ - -typedef struct leveldb_t leveldb_t; -typedef struct leveldb_cache_t leveldb_cache_t; -typedef struct leveldb_comparator_t leveldb_comparator_t; -typedef struct leveldb_env_t leveldb_env_t; -typedef struct leveldb_filelock_t leveldb_filelock_t; -typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; -typedef struct leveldb_iterator_t leveldb_iterator_t; -typedef struct leveldb_logger_t leveldb_logger_t; -typedef struct leveldb_options_t leveldb_options_t; -typedef struct leveldb_randomfile_t leveldb_randomfile_t; -typedef struct leveldb_readoptions_t leveldb_readoptions_t; -typedef struct leveldb_seqfile_t leveldb_seqfile_t; -typedef struct leveldb_snapshot_t leveldb_snapshot_t; -typedef struct leveldb_writablefile_t leveldb_writablefile_t; -typedef struct leveldb_writebatch_t leveldb_writebatch_t; -typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; - -/* DB operations */ - -extern leveldb_t* leveldb_open( - const leveldb_options_t* options, - const char* name, - char** errptr); - -extern void leveldb_close(leveldb_t* db); - -extern void leveldb_put( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - const char* val, size_t vallen, - char** errptr); - -extern void leveldb_delete( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - char** errptr); - -extern void leveldb_write( - leveldb_t* db, - const leveldb_writeoptions_t* options, - leveldb_writebatch_t* batch, - char** errptr); - -/* Returns NULL if not found. A malloc()ed array otherwise. - Stores the length of the array in *vallen. */ -extern char* leveldb_get( - leveldb_t* db, - const leveldb_readoptions_t* options, - const char* key, size_t keylen, - size_t* vallen, - char** errptr); - -extern leveldb_iterator_t* leveldb_create_iterator( - leveldb_t* db, - const leveldb_readoptions_t* options); - -extern const leveldb_snapshot_t* leveldb_create_snapshot( - leveldb_t* db); - -extern void leveldb_release_snapshot( - leveldb_t* db, - const leveldb_snapshot_t* snapshot); - -/* Returns NULL if property name is unknown. - Else returns a pointer to a malloc()-ed null-terminated value. */ -extern char* leveldb_property_value( - leveldb_t* db, - const char* propname); - -extern void leveldb_approximate_sizes( - leveldb_t* db, - int num_ranges, - const char* const* range_start_key, const size_t* range_start_key_len, - const char* const* range_limit_key, const size_t* range_limit_key_len, - uint64_t* sizes); - -extern void leveldb_compact_range( - leveldb_t* db, - const char* start_key, size_t start_key_len, - const char* limit_key, size_t limit_key_len); - -/* Management operations */ - -extern void leveldb_destroy_db( - const leveldb_options_t* options, - const char* name, - char** errptr); - -extern void leveldb_repair_db( - const leveldb_options_t* options, - const char* name, - char** errptr); - -/* Iterator */ - -extern void leveldb_iter_destroy(leveldb_iterator_t*); -extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*); -extern void leveldb_iter_seek_to_first(leveldb_iterator_t*); -extern void leveldb_iter_seek_to_last(leveldb_iterator_t*); -extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen); -extern void leveldb_iter_next(leveldb_iterator_t*); -extern void leveldb_iter_prev(leveldb_iterator_t*); -extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen); -extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen); -extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr); - -/* Write batch */ - -extern leveldb_writebatch_t* leveldb_writebatch_create(); -extern void leveldb_writebatch_destroy(leveldb_writebatch_t*); -extern void leveldb_writebatch_clear(leveldb_writebatch_t*); -extern void leveldb_writebatch_put( - leveldb_writebatch_t*, - const char* key, size_t klen, - const char* val, size_t vlen); -extern void leveldb_writebatch_delete( - leveldb_writebatch_t*, - const char* key, size_t klen); -extern void leveldb_writebatch_iterate( - leveldb_writebatch_t*, - void* state, - void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), - void (*deleted)(void*, const char* k, size_t klen)); - -/* Options */ - -extern leveldb_options_t* leveldb_options_create(); -extern void leveldb_options_destroy(leveldb_options_t*); -extern void leveldb_options_set_comparator( - leveldb_options_t*, - leveldb_comparator_t*); -extern void leveldb_options_set_filter_policy( - leveldb_options_t*, - leveldb_filterpolicy_t*); -extern void leveldb_options_set_create_if_missing( - leveldb_options_t*, unsigned char); -extern void leveldb_options_set_error_if_exists( - leveldb_options_t*, unsigned char); -extern void leveldb_options_set_paranoid_checks( - leveldb_options_t*, unsigned char); -extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); -extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*); -extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t); -extern void leveldb_options_set_max_open_files(leveldb_options_t*, int); -extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*); -extern void leveldb_options_set_block_size(leveldb_options_t*, size_t); -extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int); - -enum { - leveldb_no_compression = 0, - leveldb_snappy_compression = 1 -}; -extern void leveldb_options_set_compression(leveldb_options_t*, int); - -/* Comparator */ - -extern leveldb_comparator_t* leveldb_comparator_create( - void* state, - void (*destructor)(void*), - int (*compare)( - void*, - const char* a, size_t alen, - const char* b, size_t blen), - const char* (*name)(void*)); -extern void leveldb_comparator_destroy(leveldb_comparator_t*); - -/* Filter policy */ - -extern leveldb_filterpolicy_t* leveldb_filterpolicy_create( - void* state, - void (*destructor)(void*), - char* (*create_filter)( - void*, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length), - unsigned char (*key_may_match)( - void*, - const char* key, size_t length, - const char* filter, size_t filter_length), - const char* (*name)(void*)); -extern void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); - -extern leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( - int bits_per_key); - -/* Read options */ - -extern leveldb_readoptions_t* leveldb_readoptions_create(); -extern void leveldb_readoptions_destroy(leveldb_readoptions_t*); -extern void leveldb_readoptions_set_verify_checksums( - leveldb_readoptions_t*, - unsigned char); -extern void leveldb_readoptions_set_fill_cache( - leveldb_readoptions_t*, unsigned char); -extern void leveldb_readoptions_set_snapshot( - leveldb_readoptions_t*, - const leveldb_snapshot_t*); - -/* Write options */ - -extern leveldb_writeoptions_t* leveldb_writeoptions_create(); -extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); -extern void leveldb_writeoptions_set_sync( - leveldb_writeoptions_t*, unsigned char); - -/* Cache */ - -extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); -extern void leveldb_cache_destroy(leveldb_cache_t* cache); - -/* Env */ - -extern leveldb_env_t* leveldb_create_default_env(); -extern void leveldb_env_destroy(leveldb_env_t*); - -/* Utility */ - -/* Calls free(ptr). - REQUIRES: ptr was malloc()-ed and returned by one of the routines - in this file. Note that in certain cases (typically on Windows), you - may need to call this routine instead of free(ptr) to dispose of - malloc()-ed memory returned by this library. */ -extern void leveldb_free(void* ptr); - -/* Return the major version number for this release. */ -extern int leveldb_major_version(); - -/* Return the minor version number for this release. */ -extern int leveldb_minor_version(); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/src/leveldb/include/leveldb/cache.h b/src/leveldb/include/leveldb/cache.h deleted file mode 100644 index 5e3b47637..000000000 --- a/src/leveldb/include/leveldb/cache.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A Cache is an interface that maps keys to values. It has internal -// synchronization and may be safely accessed concurrently from -// multiple threads. It may automatically evict entries to make room -// for new entries. Values have a specified charge against the cache -// capacity. For example, a cache where the values are variable -// length strings, may use the length of the string as the charge for -// the string. -// -// A builtin cache implementation with a least-recently-used eviction -// policy is provided. Clients may use their own implementations if -// they want something more sophisticated (like scan-resistance, a -// custom eviction policy, variable cache sizing, etc.) - -#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ -#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ - -#include -#include "leveldb/slice.h" - -namespace leveldb { - -class Cache; - -// Create a new cache with a fixed size capacity. This implementation -// of Cache uses a least-recently-used eviction policy. -extern Cache* NewLRUCache(size_t capacity); - -class Cache { - public: - Cache() { } - - // Destroys all existing entries by calling the "deleter" - // function that was passed to the constructor. - virtual ~Cache(); - - // Opaque handle to an entry stored in the cache. - struct Handle { }; - - // Insert a mapping from key->value into the cache and assign it - // the specified charge against the total cache capacity. - // - // Returns a handle that corresponds to the mapping. The caller - // must call this->Release(handle) when the returned mapping is no - // longer needed. - // - // When the inserted entry is no longer needed, the key and - // value will be passed to "deleter". - virtual Handle* Insert(const Slice& key, void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)) = 0; - - // If the cache has no mapping for "key", returns NULL. - // - // Else return a handle that corresponds to the mapping. The caller - // must call this->Release(handle) when the returned mapping is no - // longer needed. - virtual Handle* Lookup(const Slice& key) = 0; - - // Release a mapping returned by a previous Lookup(). - // REQUIRES: handle must not have been released yet. - // REQUIRES: handle must have been returned by a method on *this. - virtual void Release(Handle* handle) = 0; - - // Return the value encapsulated in a handle returned by a - // successful Lookup(). - // REQUIRES: handle must not have been released yet. - // REQUIRES: handle must have been returned by a method on *this. - virtual void* Value(Handle* handle) = 0; - - // If the cache contains entry for key, erase it. Note that the - // underlying entry will be kept around until all existing handles - // to it have been released. - virtual void Erase(const Slice& key) = 0; - - // Return a new numeric id. May be used by multiple clients who are - // sharing the same cache to partition the key space. Typically the - // client will allocate a new id at startup and prepend the id to - // its cache keys. - virtual uint64_t NewId() = 0; - - private: - void LRU_Remove(Handle* e); - void LRU_Append(Handle* e); - void Unref(Handle* e); - - struct Rep; - Rep* rep_; - - // No copying allowed - Cache(const Cache&); - void operator=(const Cache&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_CACHE_H_ diff --git a/src/leveldb/include/leveldb/comparator.h b/src/leveldb/include/leveldb/comparator.h deleted file mode 100644 index 556b984c7..000000000 --- a/src/leveldb/include/leveldb/comparator.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ -#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ - -#include - -namespace leveldb { - -class Slice; - -// A Comparator object provides a total order across slices that are -// used as keys in an sstable or a database. A Comparator implementation -// must be thread-safe since leveldb may invoke its methods concurrently -// from multiple threads. -class Comparator { - public: - virtual ~Comparator(); - - // Three-way comparison. Returns value: - // < 0 iff "a" < "b", - // == 0 iff "a" == "b", - // > 0 iff "a" > "b" - virtual int Compare(const Slice& a, const Slice& b) const = 0; - - // The name of the comparator. Used to check for comparator - // mismatches (i.e., a DB created with one comparator is - // accessed using a different comparator. - // - // The client of this package should switch to a new name whenever - // the comparator implementation changes in a way that will cause - // the relative ordering of any two keys to change. - // - // Names starting with "leveldb." are reserved and should not be used - // by any clients of this package. - virtual const char* Name() const = 0; - - // Advanced functions: these are used to reduce the space requirements - // for internal data structures like index blocks. - - // If *start < limit, changes *start to a short string in [start,limit). - // Simple comparator implementations may return with *start unchanged, - // i.e., an implementation of this method that does nothing is correct. - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const = 0; - - // Changes *key to a short string >= *key. - // Simple comparator implementations may return with *key unchanged, - // i.e., an implementation of this method that does nothing is correct. - virtual void FindShortSuccessor(std::string* key) const = 0; -}; - -// Return a builtin comparator that uses lexicographic byte-wise -// ordering. The result remains the property of this module and -// must not be deleted. -extern const Comparator* BytewiseComparator(); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h deleted file mode 100644 index 29d367447..000000000 --- a/src/leveldb/include/leveldb/db.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_ -#define STORAGE_LEVELDB_INCLUDE_DB_H_ - -#include -#include -#include "leveldb/iterator.h" -#include "leveldb/options.h" - -namespace leveldb { - -// Update Makefile if you change these -static const int kMajorVersion = 1; -static const int kMinorVersion = 9; - -struct Options; -struct ReadOptions; -struct WriteOptions; -class WriteBatch; - -// Abstract handle to particular state of a DB. -// A Snapshot is an immutable object and can therefore be safely -// accessed from multiple threads without any external synchronization. -class Snapshot { - protected: - virtual ~Snapshot(); -}; - -// A range of keys -struct Range { - Slice start; // Included in the range - Slice limit; // Not included in the range - - Range() { } - Range(const Slice& s, const Slice& l) : start(s), limit(l) { } -}; - -// A DB is a persistent ordered map from keys to values. -// A DB is safe for concurrent access from multiple threads without -// any external synchronization. -class DB { - public: - // Open the database with the specified "name". - // Stores a pointer to a heap-allocated database in *dbptr and returns - // OK on success. - // Stores NULL in *dbptr and returns a non-OK status on error. - // Caller should delete *dbptr when it is no longer needed. - static Status Open(const Options& options, - const std::string& name, - DB** dbptr); - - DB() { } - virtual ~DB(); - - // Set the database entry for "key" to "value". Returns OK on success, - // and a non-OK status on error. - // Note: consider setting options.sync = true. - virtual Status Put(const WriteOptions& options, - const Slice& key, - const Slice& value) = 0; - - // Remove the database entry (if any) for "key". Returns OK on - // success, and a non-OK status on error. It is not an error if "key" - // did not exist in the database. - // Note: consider setting options.sync = true. - virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; - - // Apply the specified updates to the database. - // Returns OK on success, non-OK on failure. - // Note: consider setting options.sync = true. - virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; - - // If the database contains an entry for "key" store the - // corresponding value in *value and return OK. - // - // If there is no entry for "key" leave *value unchanged and return - // a status for which Status::IsNotFound() returns true. - // - // May return some other Status on an error. - virtual Status Get(const ReadOptions& options, - const Slice& key, std::string* value) = 0; - - // Return a heap-allocated iterator over the contents of the database. - // The result of NewIterator() is initially invalid (caller must - // call one of the Seek methods on the iterator before using it). - // - // Caller should delete the iterator when it is no longer needed. - // The returned iterator should be deleted before this db is deleted. - virtual Iterator* NewIterator(const ReadOptions& options) = 0; - - // Return a handle to the current DB state. Iterators created with - // this handle will all observe a stable snapshot of the current DB - // state. The caller must call ReleaseSnapshot(result) when the - // snapshot is no longer needed. - virtual const Snapshot* GetSnapshot() = 0; - - // Release a previously acquired snapshot. The caller must not - // use "snapshot" after this call. - virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; - - // DB implementations can export properties about their state - // via this method. If "property" is a valid property understood by this - // DB implementation, fills "*value" with its current value and returns - // true. Otherwise returns false. - // - // - // Valid property names include: - // - // "leveldb.num-files-at-level" - return the number of files at level , - // where is an ASCII representation of a level number (e.g. "0"). - // "leveldb.stats" - returns a multi-line string that describes statistics - // about the internal operation of the DB. - // "leveldb.sstables" - returns a multi-line string that describes all - // of the sstables that make up the db contents. - virtual bool GetProperty(const Slice& property, std::string* value) = 0; - - // For each i in [0,n-1], store in "sizes[i]", the approximate - // file system space used by keys in "[range[i].start .. range[i].limit)". - // - // Note that the returned sizes measure file system space usage, so - // if the user data compresses by a factor of ten, the returned - // sizes will be one-tenth the size of the corresponding user data size. - // - // The results may not include the sizes of recently written data. - virtual void GetApproximateSizes(const Range* range, int n, - uint64_t* sizes) = 0; - - // Compact the underlying storage for the key range [*begin,*end]. - // In particular, deleted and overwritten versions are discarded, - // and the data is rearranged to reduce the cost of operations - // needed to access the data. This operation should typically only - // be invoked by users who understand the underlying implementation. - // - // begin==NULL is treated as a key before all keys in the database. - // end==NULL is treated as a key after all keys in the database. - // Therefore the following call will compact the entire database: - // db->CompactRange(NULL, NULL); - virtual void CompactRange(const Slice* begin, const Slice* end) = 0; - - private: - // No copying allowed - DB(const DB&); - void operator=(const DB&); -}; - -// Destroy the contents of the specified database. -// Be very careful using this method. -Status DestroyDB(const std::string& name, const Options& options); - -// If a DB cannot be opened, you may attempt to call this method to -// resurrect as much of the contents of the database as possible. -// Some data may be lost, so be careful when calling this function -// on a database that contains important information. -Status RepairDB(const std::string& dbname, const Options& options); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h deleted file mode 100644 index fa32289f5..000000000 --- a/src/leveldb/include/leveldb/env.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// An Env is an interface used by the leveldb implementation to access -// operating system functionality like the filesystem etc. Callers -// may wish to provide a custom Env object when opening a database to -// get fine gain control; e.g., to rate limit file system operations. -// -// All Env implementations are safe for concurrent access from -// multiple threads without any external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ -#define STORAGE_LEVELDB_INCLUDE_ENV_H_ - -#include -#include -#include -#include -#include "leveldb/status.h" - -namespace leveldb { - -class FileLock; -class Logger; -class RandomAccessFile; -class SequentialFile; -class Slice; -class WritableFile; - -class Env { - public: - Env() { } - virtual ~Env(); - - // Return a default environment suitable for the current operating - // system. Sophisticated users may wish to provide their own Env - // implementation instead of relying on this default environment. - // - // The result of Default() belongs to leveldb and must never be deleted. - static Env* Default(); - - // Create a brand new sequentially-readable file with the specified name. - // On success, stores a pointer to the new file in *result and returns OK. - // On failure stores NULL in *result and returns non-OK. If the file does - // not exist, returns a non-OK status. - // - // The returned file will only be accessed by one thread at a time. - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result) = 0; - - // Create a brand new random access read-only file with the - // specified name. On success, stores a pointer to the new file in - // *result and returns OK. On failure stores NULL in *result and - // returns non-OK. If the file does not exist, returns a non-OK - // status. - // - // The returned file may be concurrently accessed by multiple threads. - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) = 0; - - // Create an object that writes to a new file with the specified - // name. Deletes any existing file with the same name and creates a - // new file. On success, stores a pointer to the new file in - // *result and returns OK. On failure stores NULL in *result and - // returns non-OK. - // - // The returned file will only be accessed by one thread at a time. - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) = 0; - - // Returns true iff the named file exists. - virtual bool FileExists(const std::string& fname) = 0; - - // Store in *result the names of the children of the specified directory. - // The names are relative to "dir". - // Original contents of *results are dropped. - virtual Status GetChildren(const std::string& dir, - std::vector* result) = 0; - - // Delete the named file. - virtual Status DeleteFile(const std::string& fname) = 0; - - // Create the specified directory. - virtual Status CreateDir(const std::string& dirname) = 0; - - // Delete the specified directory. - virtual Status DeleteDir(const std::string& dirname) = 0; - - // Store the size of fname in *file_size. - virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; - - // Rename file src to target. - virtual Status RenameFile(const std::string& src, - const std::string& target) = 0; - - // Lock the specified file. Used to prevent concurrent access to - // the same db by multiple processes. On failure, stores NULL in - // *lock and returns non-OK. - // - // On success, stores a pointer to the object that represents the - // acquired lock in *lock and returns OK. The caller should call - // UnlockFile(*lock) to release the lock. If the process exits, - // the lock will be automatically released. - // - // If somebody else already holds the lock, finishes immediately - // with a failure. I.e., this call does not wait for existing locks - // to go away. - // - // May create the named file if it does not already exist. - virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; - - // Release the lock acquired by a previous successful call to LockFile. - // REQUIRES: lock was returned by a successful LockFile() call - // REQUIRES: lock has not already been unlocked. - virtual Status UnlockFile(FileLock* lock) = 0; - - // Arrange to run "(*function)(arg)" once in a background thread. - // - // "function" may run in an unspecified thread. Multiple functions - // added to the same Env may run concurrently in different threads. - // I.e., the caller may not assume that background work items are - // serialized. - virtual void Schedule( - void (*function)(void* arg), - void* arg) = 0; - - // Start a new thread, invoking "function(arg)" within the new thread. - // When "function(arg)" returns, the thread will be destroyed. - virtual void StartThread(void (*function)(void* arg), void* arg) = 0; - - // *path is set to a temporary directory that can be used for testing. It may - // or many not have just been created. The directory may or may not differ - // between runs of the same process, but subsequent calls will return the - // same directory. - virtual Status GetTestDirectory(std::string* path) = 0; - - // Create and return a log file for storing informational messages. - virtual Status NewLogger(const std::string& fname, Logger** result) = 0; - - // Returns the number of micro-seconds since some fixed point in time. Only - // useful for computing deltas of time. - virtual uint64_t NowMicros() = 0; - - // Sleep/delay the thread for the perscribed number of micro-seconds. - virtual void SleepForMicroseconds(int micros) = 0; - - private: - // No copying allowed - Env(const Env&); - void operator=(const Env&); -}; - -// A file abstraction for reading sequentially through a file -class SequentialFile { - public: - SequentialFile() { } - virtual ~SequentialFile(); - - // Read up to "n" bytes from the file. "scratch[0..n-1]" may be - // written by this routine. Sets "*result" to the data that was - // read (including if fewer than "n" bytes were successfully read). - // May set "*result" to point at data in "scratch[0..n-1]", so - // "scratch[0..n-1]" must be live when "*result" is used. - // If an error was encountered, returns a non-OK status. - // - // REQUIRES: External synchronization - virtual Status Read(size_t n, Slice* result, char* scratch) = 0; - - // Skip "n" bytes from the file. This is guaranteed to be no - // slower that reading the same data, but may be faster. - // - // If end of file is reached, skipping will stop at the end of the - // file, and Skip will return OK. - // - // REQUIRES: External synchronization - virtual Status Skip(uint64_t n) = 0; - - private: - // No copying allowed - SequentialFile(const SequentialFile&); - void operator=(const SequentialFile&); -}; - -// A file abstraction for randomly reading the contents of a file. -class RandomAccessFile { - public: - RandomAccessFile() { } - virtual ~RandomAccessFile(); - - // Read up to "n" bytes from the file starting at "offset". - // "scratch[0..n-1]" may be written by this routine. Sets "*result" - // to the data that was read (including if fewer than "n" bytes were - // successfully read). May set "*result" to point at data in - // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when - // "*result" is used. If an error was encountered, returns a non-OK - // status. - // - // Safe for concurrent use by multiple threads. - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const = 0; - - private: - // No copying allowed - RandomAccessFile(const RandomAccessFile&); - void operator=(const RandomAccessFile&); -}; - -// A file abstraction for sequential writing. The implementation -// must provide buffering since callers may append small fragments -// at a time to the file. -class WritableFile { - public: - WritableFile() { } - virtual ~WritableFile(); - - virtual Status Append(const Slice& data) = 0; - virtual Status Close() = 0; - virtual Status Flush() = 0; - virtual Status Sync() = 0; - - private: - // No copying allowed - WritableFile(const WritableFile&); - void operator=(const WritableFile&); -}; - -// An interface for writing log messages. -class Logger { - public: - Logger() { } - virtual ~Logger(); - - // Write an entry to the log file with the specified format. - virtual void Logv(const char* format, va_list ap) = 0; - - private: - // No copying allowed - Logger(const Logger&); - void operator=(const Logger&); -}; - - -// Identifies a locked file. -class FileLock { - public: - FileLock() { } - virtual ~FileLock(); - private: - // No copying allowed - FileLock(const FileLock&); - void operator=(const FileLock&); -}; - -// Log the specified data to *info_log if info_log is non-NULL. -extern void Log(Logger* info_log, const char* format, ...) -# if defined(__GNUC__) || defined(__clang__) - __attribute__((__format__ (__printf__, 2, 3))) -# endif - ; - -// A utility routine: write "data" to the named file. -extern Status WriteStringToFile(Env* env, const Slice& data, - const std::string& fname); - -// A utility routine: read contents of named file into *data -extern Status ReadFileToString(Env* env, const std::string& fname, - std::string* data); - -// An implementation of Env that forwards all calls to another Env. -// May be useful to clients who wish to override just part of the -// functionality of another Env. -class EnvWrapper : public Env { - public: - // Initialize an EnvWrapper that delegates all calls to *t - explicit EnvWrapper(Env* t) : target_(t) { } - virtual ~EnvWrapper(); - - // Return the target to which this Env forwards all calls - Env* target() const { return target_; } - - // The following text is boilerplate that forwards all methods to target() - Status NewSequentialFile(const std::string& f, SequentialFile** r) { - return target_->NewSequentialFile(f, r); - } - Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { - return target_->NewRandomAccessFile(f, r); - } - Status NewWritableFile(const std::string& f, WritableFile** r) { - return target_->NewWritableFile(f, r); - } - bool FileExists(const std::string& f) { return target_->FileExists(f); } - Status GetChildren(const std::string& dir, std::vector* r) { - return target_->GetChildren(dir, r); - } - Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); } - Status CreateDir(const std::string& d) { return target_->CreateDir(d); } - Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); } - Status GetFileSize(const std::string& f, uint64_t* s) { - return target_->GetFileSize(f, s); - } - Status RenameFile(const std::string& s, const std::string& t) { - return target_->RenameFile(s, t); - } - Status LockFile(const std::string& f, FileLock** l) { - return target_->LockFile(f, l); - } - Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); } - void Schedule(void (*f)(void*), void* a) { - return target_->Schedule(f, a); - } - void StartThread(void (*f)(void*), void* a) { - return target_->StartThread(f, a); - } - virtual Status GetTestDirectory(std::string* path) { - return target_->GetTestDirectory(path); - } - virtual Status NewLogger(const std::string& fname, Logger** result) { - return target_->NewLogger(fname, result); - } - uint64_t NowMicros() { - return target_->NowMicros(); - } - void SleepForMicroseconds(int micros) { - target_->SleepForMicroseconds(micros); - } - private: - Env* target_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/src/leveldb/include/leveldb/filter_policy.h b/src/leveldb/include/leveldb/filter_policy.h deleted file mode 100644 index 1fba08001..000000000 --- a/src/leveldb/include/leveldb/filter_policy.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A database can be configured with a custom FilterPolicy object. -// This object is responsible for creating a small filter from a set -// of keys. These filters are stored in leveldb and are consulted -// automatically by leveldb to decide whether or not to read some -// information from disk. In many cases, a filter can cut down the -// number of disk seeks form a handful to a single disk seek per -// DB::Get() call. -// -// Most people will want to use the builtin bloom filter support (see -// NewBloomFilterPolicy() below). - -#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ -#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ - -#include - -namespace leveldb { - -class Slice; - -class FilterPolicy { - public: - virtual ~FilterPolicy(); - - // Return the name of this policy. Note that if the filter encoding - // changes in an incompatible way, the name returned by this method - // must be changed. Otherwise, old incompatible filters may be - // passed to methods of this type. - virtual const char* Name() const = 0; - - // keys[0,n-1] contains a list of keys (potentially with duplicates) - // that are ordered according to the user supplied comparator. - // Append a filter that summarizes keys[0,n-1] to *dst. - // - // Warning: do not change the initial contents of *dst. Instead, - // append the newly constructed filter to *dst. - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) - const = 0; - - // "filter" contains the data appended by a preceding call to - // CreateFilter() on this class. This method must return true if - // the key was in the list of keys passed to CreateFilter(). - // This method may return true or false if the key was not on the - // list, but it should aim to return false with a high probability. - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; -}; - -// Return a new filter policy that uses a bloom filter with approximately -// the specified number of bits per key. A good value for bits_per_key -// is 10, which yields a filter with ~ 1% false positive rate. -// -// Callers must delete the result after any database that is using the -// result has been closed. -// -// Note: if you are using a custom comparator that ignores some parts -// of the keys being compared, you must not use NewBloomFilterPolicy() -// and must provide your own FilterPolicy that also ignores the -// corresponding parts of the keys. For example, if the comparator -// ignores trailing spaces, it would be incorrect to use a -// FilterPolicy (like NewBloomFilterPolicy) that does not ignore -// trailing spaces in keys. -extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); - -} - -#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/src/leveldb/include/leveldb/iterator.h b/src/leveldb/include/leveldb/iterator.h deleted file mode 100644 index ad543eb46..000000000 --- a/src/leveldb/include/leveldb/iterator.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// An iterator yields a sequence of key/value pairs from a source. -// The following class defines the interface. Multiple implementations -// are provided by this library. In particular, iterators are provided -// to access the contents of a Table or a DB. -// -// Multiple threads can invoke const methods on an Iterator without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same Iterator must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ -#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ - -#include "leveldb/slice.h" -#include "leveldb/status.h" - -namespace leveldb { - -class Iterator { - public: - Iterator(); - virtual ~Iterator(); - - // An iterator is either positioned at a key/value pair, or - // not valid. This method returns true iff the iterator is valid. - virtual bool Valid() const = 0; - - // Position at the first key in the source. The iterator is Valid() - // after this call iff the source is not empty. - virtual void SeekToFirst() = 0; - - // Position at the last key in the source. The iterator is - // Valid() after this call iff the source is not empty. - virtual void SeekToLast() = 0; - - // Position at the first key in the source that at or past target - // The iterator is Valid() after this call iff the source contains - // an entry that comes at or past target. - virtual void Seek(const Slice& target) = 0; - - // Moves to the next entry in the source. After this call, Valid() is - // true iff the iterator was not positioned at the last entry in the source. - // REQUIRES: Valid() - virtual void Next() = 0; - - // Moves to the previous entry in the source. After this call, Valid() is - // true iff the iterator was not positioned at the first entry in source. - // REQUIRES: Valid() - virtual void Prev() = 0; - - // Return the key for the current entry. The underlying storage for - // the returned slice is valid only until the next modification of - // the iterator. - // REQUIRES: Valid() - virtual Slice key() const = 0; - - // Return the value for the current entry. The underlying storage for - // the returned slice is valid only until the next modification of - // the iterator. - // REQUIRES: !AtEnd() && !AtStart() - virtual Slice value() const = 0; - - // If an error has occurred, return it. Else return an ok status. - virtual Status status() const = 0; - - // Clients are allowed to register function/arg1/arg2 triples that - // will be invoked when this iterator is destroyed. - // - // Note that unlike all of the preceding methods, this method is - // not abstract and therefore clients should not override it. - typedef void (*CleanupFunction)(void* arg1, void* arg2); - void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); - - private: - struct Cleanup { - CleanupFunction function; - void* arg1; - void* arg2; - Cleanup* next; - }; - Cleanup cleanup_; - - // No copying allowed - Iterator(const Iterator&); - void operator=(const Iterator&); -}; - -// Return an empty iterator (yields nothing). -extern Iterator* NewEmptyIterator(); - -// Return an empty iterator with the specified status. -extern Iterator* NewErrorIterator(const Status& status); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h deleted file mode 100644 index fdda718d3..000000000 --- a/src/leveldb/include/leveldb/options.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ -#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ - -#include - -namespace leveldb { - -class Cache; -class Comparator; -class Env; -class FilterPolicy; -class Logger; -class Snapshot; - -// DB contents are stored in a set of blocks, each of which holds a -// sequence of key,value pairs. Each block may be compressed before -// being stored in a file. The following enum describes which -// compression method (if any) is used to compress a block. -enum CompressionType { - // NOTE: do not change the values of existing entries, as these are - // part of the persistent format on disk. - kNoCompression = 0x0, - kSnappyCompression = 0x1 -}; - -// Options to control the behavior of a database (passed to DB::Open) -struct Options { - // ------------------- - // Parameters that affect behavior - - // Comparator used to define the order of keys in the table. - // Default: a comparator that uses lexicographic byte-wise ordering - // - // REQUIRES: The client must ensure that the comparator supplied - // here has the same name and orders keys *exactly* the same as the - // comparator provided to previous open calls on the same DB. - const Comparator* comparator; - - // If true, the database will be created if it is missing. - // Default: false - bool create_if_missing; - - // If true, an error is raised if the database already exists. - // Default: false - bool error_if_exists; - - // If true, the implementation will do aggressive checking of the - // data it is processing and will stop early if it detects any - // errors. This may have unforeseen ramifications: for example, a - // corruption of one DB entry may cause a large number of entries to - // become unreadable or for the entire DB to become unopenable. - // Default: false - bool paranoid_checks; - - // Use the specified object to interact with the environment, - // e.g. to read/write files, schedule background work, etc. - // Default: Env::Default() - Env* env; - - // Any internal progress/error information generated by the db will - // be written to info_log if it is non-NULL, or to a file stored - // in the same directory as the DB contents if info_log is NULL. - // Default: NULL - Logger* info_log; - - // ------------------- - // Parameters that affect performance - - // Amount of data to build up in memory (backed by an unsorted log - // on disk) before converting to a sorted on-disk file. - // - // Larger values increase performance, especially during bulk loads. - // Up to two write buffers may be held in memory at the same time, - // so you may wish to adjust this parameter to control memory usage. - // Also, a larger write buffer will result in a longer recovery time - // the next time the database is opened. - // - // Default: 4MB - size_t write_buffer_size; - - // Number of open files that can be used by the DB. You may need to - // increase this if your database has a large working set (budget - // one open file per 2MB of working set). - // - // Default: 1000 - int max_open_files; - - // Control over blocks (user data is stored in a set of blocks, and - // a block is the unit of reading from disk). - - // If non-NULL, use the specified cache for blocks. - // If NULL, leveldb will automatically create and use an 8MB internal cache. - // Default: NULL - Cache* block_cache; - - // Approximate size of user data packed per block. Note that the - // block size specified here corresponds to uncompressed data. The - // actual size of the unit read from disk may be smaller if - // compression is enabled. This parameter can be changed dynamically. - // - // Default: 4K - size_t block_size; - - // Number of keys between restart points for delta encoding of keys. - // This parameter can be changed dynamically. Most clients should - // leave this parameter alone. - // - // Default: 16 - int block_restart_interval; - - // Compress blocks using the specified compression algorithm. This - // parameter can be changed dynamically. - // - // Default: kSnappyCompression, which gives lightweight but fast - // compression. - // - // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: - // ~200-500MB/s compression - // ~400-800MB/s decompression - // Note that these speeds are significantly faster than most - // persistent storage speeds, and therefore it is typically never - // worth switching to kNoCompression. Even if the input data is - // incompressible, the kSnappyCompression implementation will - // efficiently detect that and will switch to uncompressed mode. - CompressionType compression; - - // If non-NULL, use the specified filter policy to reduce disk reads. - // Many applications will benefit from passing the result of - // NewBloomFilterPolicy() here. - // - // Default: NULL - const FilterPolicy* filter_policy; - - // Create an Options object with default values for all fields. - Options(); -}; - -// Options that control read operations -struct ReadOptions { - // If true, all data read from underlying storage will be - // verified against corresponding checksums. - // Default: false - bool verify_checksums; - - // Should the data read for this iteration be cached in memory? - // Callers may wish to set this field to false for bulk scans. - // Default: true - bool fill_cache; - - // If "snapshot" is non-NULL, read as of the supplied snapshot - // (which must belong to the DB that is being read and which must - // not have been released). If "snapshot" is NULL, use an impliicit - // snapshot of the state at the beginning of this read operation. - // Default: NULL - const Snapshot* snapshot; - - ReadOptions() - : verify_checksums(false), - fill_cache(true), - snapshot(NULL) { - } -}; - -// Options that control write operations -struct WriteOptions { - // If true, the write will be flushed from the operating system - // buffer cache (by calling WritableFile::Sync()) before the write - // is considered complete. If this flag is true, writes will be - // slower. - // - // If this flag is false, and the machine crashes, some recent - // writes may be lost. Note that if it is just the process that - // crashes (i.e., the machine does not reboot), no writes will be - // lost even if sync==false. - // - // In other words, a DB write with sync==false has similar - // crash semantics as the "write()" system call. A DB write - // with sync==true has similar crash semantics to a "write()" - // system call followed by "fsync()". - // - // Default: false - bool sync; - - WriteOptions() - : sync(false) { - } -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/src/leveldb/include/leveldb/slice.h b/src/leveldb/include/leveldb/slice.h deleted file mode 100644 index 74ea8fa49..000000000 --- a/src/leveldb/include/leveldb/slice.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Slice is a simple structure containing a pointer into some external -// storage and a size. The user of a Slice must ensure that the slice -// is not used after the corresponding external storage has been -// deallocated. -// -// Multiple threads can invoke const methods on a Slice without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same Slice must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ -#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ - -#include -#include -#include -#include - -namespace leveldb { - -class Slice { - public: - // Create an empty slice. - Slice() : data_(""), size_(0) { } - - // Create a slice that refers to d[0,n-1]. - Slice(const char* d, size_t n) : data_(d), size_(n) { } - - // Create a slice that refers to the contents of "s" - Slice(const std::string& s) : data_(s.data()), size_(s.size()) { } - - // Create a slice that refers to s[0,strlen(s)-1] - Slice(const char* s) : data_(s), size_(strlen(s)) { } - - // Return a pointer to the beginning of the referenced data - const char* data() const { return data_; } - - // Return the length (in bytes) of the referenced data - size_t size() const { return size_; } - - // Return true iff the length of the referenced data is zero - bool empty() const { return size_ == 0; } - - // Return the ith byte in the referenced data. - // REQUIRES: n < size() - char operator[](size_t n) const { - assert(n < size()); - return data_[n]; - } - - // Change this slice to refer to an empty array - void clear() { data_ = ""; size_ = 0; } - - // Drop the first "n" bytes from this slice. - void remove_prefix(size_t n) { - assert(n <= size()); - data_ += n; - size_ -= n; - } - - // Return a string that contains the copy of the referenced data. - std::string ToString() const { return std::string(data_, size_); } - - // Three-way comparison. Returns value: - // < 0 iff "*this" < "b", - // == 0 iff "*this" == "b", - // > 0 iff "*this" > "b" - int compare(const Slice& b) const; - - // Return true iff "x" is a prefix of "*this" - bool starts_with(const Slice& x) const { - return ((size_ >= x.size_) && - (memcmp(data_, x.data_, x.size_) == 0)); - } - - private: - const char* data_; - size_t size_; - - // Intentionally copyable -}; - -inline bool operator==(const Slice& x, const Slice& y) { - return ((x.size() == y.size()) && - (memcmp(x.data(), y.data(), x.size()) == 0)); -} - -inline bool operator!=(const Slice& x, const Slice& y) { - return !(x == y); -} - -inline int Slice::compare(const Slice& b) const { - const int min_len = (size_ < b.size_) ? size_ : b.size_; - int r = memcmp(data_, b.data_, min_len); - if (r == 0) { - if (size_ < b.size_) r = -1; - else if (size_ > b.size_) r = +1; - } - return r; -} - -} // namespace leveldb - - -#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/src/leveldb/include/leveldb/status.h b/src/leveldb/include/leveldb/status.h deleted file mode 100644 index 11dbd4b47..000000000 --- a/src/leveldb/include/leveldb/status.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A Status encapsulates the result of an operation. It may indicate success, -// or it may indicate an error with an associated error message. -// -// Multiple threads can invoke const methods on a Status without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same Status must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ -#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ - -#include -#include "leveldb/slice.h" - -namespace leveldb { - -class Status { - public: - // Create a success status. - Status() : state_(NULL) { } - ~Status() { delete[] state_; } - - // Copy the specified status. - Status(const Status& s); - void operator=(const Status& s); - - // Return a success status. - static Status OK() { return Status(); } - - // Return error status of an appropriate type. - static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kNotFound, msg, msg2); - } - static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kCorruption, msg, msg2); - } - static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kNotSupported, msg, msg2); - } - static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kInvalidArgument, msg, msg2); - } - static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kIOError, msg, msg2); - } - - // Returns true iff the status indicates success. - bool ok() const { return (state_ == NULL); } - - // Returns true iff the status indicates a NotFound error. - bool IsNotFound() const { return code() == kNotFound; } - - // Returns true iff the status indicates a Corruption error. - bool IsCorruption() const { return code() == kCorruption; } - - // Returns true iff the status indicates an IOError. - bool IsIOError() const { return code() == kIOError; } - - // Return a string representation of this status suitable for printing. - // Returns the string "OK" for success. - std::string ToString() const; - - private: - // OK status has a NULL state_. Otherwise, state_ is a new[] array - // of the following form: - // state_[0..3] == length of message - // state_[4] == code - // state_[5..] == message - const char* state_; - - enum Code { - kOk = 0, - kNotFound = 1, - kCorruption = 2, - kNotSupported = 3, - kInvalidArgument = 4, - kIOError = 5 - }; - - Code code() const { - return (state_ == NULL) ? kOk : static_cast(state_[4]); - } - - Status(Code code, const Slice& msg, const Slice& msg2); - static const char* CopyState(const char* s); -}; - -inline Status::Status(const Status& s) { - state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); -} -inline void Status::operator=(const Status& s) { - // The following condition catches both aliasing (when this == &s), - // and the common case where both s and *this are ok. - if (state_ != s.state_) { - delete[] state_; - state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); - } -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/src/leveldb/include/leveldb/table.h b/src/leveldb/include/leveldb/table.h deleted file mode 100644 index a9746c3f5..000000000 --- a/src/leveldb/include/leveldb/table.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_ -#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ - -#include -#include "leveldb/iterator.h" - -namespace leveldb { - -class Block; -class BlockHandle; -class Footer; -struct Options; -class RandomAccessFile; -struct ReadOptions; -class TableCache; - -// A Table is a sorted map from strings to strings. Tables are -// immutable and persistent. A Table may be safely accessed from -// multiple threads without external synchronization. -class Table { - public: - // Attempt to open the table that is stored in bytes [0..file_size) - // of "file", and read the metadata entries necessary to allow - // retrieving data from the table. - // - // If successful, returns ok and sets "*table" to the newly opened - // table. The client should delete "*table" when no longer needed. - // If there was an error while initializing the table, sets "*table" - // to NULL and returns a non-ok status. Does not take ownership of - // "*source", but the client must ensure that "source" remains live - // for the duration of the returned table's lifetime. - // - // *file must remain live while this Table is in use. - static Status Open(const Options& options, - RandomAccessFile* file, - uint64_t file_size, - Table** table); - - ~Table(); - - // Returns a new iterator over the table contents. - // The result of NewIterator() is initially invalid (caller must - // call one of the Seek methods on the iterator before using it). - Iterator* NewIterator(const ReadOptions&) const; - - // Given a key, return an approximate byte offset in the file where - // the data for that key begins (or would begin if the key were - // present in the file). The returned value is in terms of file - // bytes, and so includes effects like compression of the underlying data. - // E.g., the approximate offset of the last key in the table will - // be close to the file length. - uint64_t ApproximateOffsetOf(const Slice& key) const; - - private: - struct Rep; - Rep* rep_; - - explicit Table(Rep* rep) { rep_ = rep; } - static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); - - // Calls (*handle_result)(arg, ...) with the entry found after a call - // to Seek(key). May not make such a call if filter policy says - // that key is not present. - friend class TableCache; - Status InternalGet( - const ReadOptions&, const Slice& key, - void* arg, - void (*handle_result)(void* arg, const Slice& k, const Slice& v)); - - - void ReadMeta(const Footer& footer); - void ReadFilter(const Slice& filter_handle_value); - - // No copying allowed - Table(const Table&); - void operator=(const Table&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/src/leveldb/include/leveldb/table_builder.h b/src/leveldb/include/leveldb/table_builder.h deleted file mode 100644 index 5fd1dc71f..000000000 --- a/src/leveldb/include/leveldb/table_builder.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// TableBuilder provides the interface used to build a Table -// (an immutable and sorted map from keys to values). -// -// Multiple threads can invoke const methods on a TableBuilder without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same TableBuilder must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ -#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ - -#include -#include "leveldb/options.h" -#include "leveldb/status.h" - -namespace leveldb { - -class BlockBuilder; -class BlockHandle; -class WritableFile; - -class TableBuilder { - public: - // Create a builder that will store the contents of the table it is - // building in *file. Does not close the file. It is up to the - // caller to close the file after calling Finish(). - TableBuilder(const Options& options, WritableFile* file); - - // REQUIRES: Either Finish() or Abandon() has been called. - ~TableBuilder(); - - // Change the options used by this builder. Note: only some of the - // option fields can be changed after construction. If a field is - // not allowed to change dynamically and its value in the structure - // passed to the constructor is different from its value in the - // structure passed to this method, this method will return an error - // without changing any fields. - Status ChangeOptions(const Options& options); - - // Add key,value to the table being constructed. - // REQUIRES: key is after any previously added key according to comparator. - // REQUIRES: Finish(), Abandon() have not been called - void Add(const Slice& key, const Slice& value); - - // Advanced operation: flush any buffered key/value pairs to file. - // Can be used to ensure that two adjacent entries never live in - // the same data block. Most clients should not need to use this method. - // REQUIRES: Finish(), Abandon() have not been called - void Flush(); - - // Return non-ok iff some error has been detected. - Status status() const; - - // Finish building the table. Stops using the file passed to the - // constructor after this function returns. - // REQUIRES: Finish(), Abandon() have not been called - Status Finish(); - - // Indicate that the contents of this builder should be abandoned. Stops - // using the file passed to the constructor after this function returns. - // If the caller is not going to call Finish(), it must call Abandon() - // before destroying this builder. - // REQUIRES: Finish(), Abandon() have not been called - void Abandon(); - - // Number of calls to Add() so far. - uint64_t NumEntries() const; - - // Size of the file generated so far. If invoked after a successful - // Finish() call, returns the size of the final generated file. - uint64_t FileSize() const; - - private: - bool ok() const { return status().ok(); } - void WriteBlock(BlockBuilder* block, BlockHandle* handle); - void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); - - struct Rep; - Rep* rep_; - - // No copying allowed - TableBuilder(const TableBuilder&); - void operator=(const TableBuilder&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/src/leveldb/include/leveldb/write_batch.h b/src/leveldb/include/leveldb/write_batch.h deleted file mode 100644 index ee9aab68e..000000000 --- a/src/leveldb/include/leveldb/write_batch.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// WriteBatch holds a collection of updates to apply atomically to a DB. -// -// The updates are applied in the order in which they are added -// to the WriteBatch. For example, the value of "key" will be "v3" -// after the following batch is written: -// -// batch.Put("key", "v1"); -// batch.Delete("key"); -// batch.Put("key", "v2"); -// batch.Put("key", "v3"); -// -// Multiple threads can invoke const methods on a WriteBatch without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same WriteBatch must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ -#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ - -#include -#include "leveldb/status.h" - -namespace leveldb { - -class Slice; - -class WriteBatch { - public: - WriteBatch(); - ~WriteBatch(); - - // Store the mapping "key->value" in the database. - void Put(const Slice& key, const Slice& value); - - // If the database contains a mapping for "key", erase it. Else do nothing. - void Delete(const Slice& key); - - // Clear all updates buffered in this batch. - void Clear(); - - // Support for iterating over the contents of a batch. - class Handler { - public: - virtual ~Handler(); - virtual void Put(const Slice& key, const Slice& value) = 0; - virtual void Delete(const Slice& key) = 0; - }; - Status Iterate(Handler* handler) const; - - private: - friend class WriteBatchInternal; - - std::string rep_; // See comment in write_batch.cc for the format of rep_ - - // Intentionally copyable -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/src/leveldb/port/README b/src/leveldb/port/README deleted file mode 100644 index 422563e25..000000000 --- a/src/leveldb/port/README +++ /dev/null @@ -1,10 +0,0 @@ -This directory contains interfaces and implementations that isolate the -rest of the package from platform details. - -Code in the rest of the package includes "port.h" from this directory. -"port.h" in turn includes a platform specific "port_.h" file -that provides the platform specific implementation. - -See port_posix.h for an example of what must be provided in a platform -specific header file. - diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h deleted file mode 100644 index e17bf435e..000000000 --- a/src/leveldb/port/atomic_pointer.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// AtomicPointer provides storage for a lock-free pointer. -// Platform-dependent implementation of AtomicPointer: -// - If the platform provides a cheap barrier, we use it with raw pointers -// - If cstdatomic is present (on newer versions of gcc, it is), we use -// a cstdatomic-based AtomicPointer. However we prefer the memory -// barrier based version, because at least on a gcc 4.4 32-bit build -// on linux, we have encountered a buggy -// implementation. Also, some implementations are much -// slower than a memory-barrier based implementation (~16ns for -// based acquire-load vs. ~1ns for a barrier based -// acquire-load). -// This code is based on atomicops-internals-* in Google's perftools: -// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase - -#ifndef PORT_ATOMIC_POINTER_H_ -#define PORT_ATOMIC_POINTER_H_ - -#include -#ifdef LEVELDB_CSTDATOMIC_PRESENT -#include -#endif -#ifdef OS_WIN -#include -#endif -#ifdef OS_MACOSX -#include -#endif - -#if defined(_M_X64) || defined(__x86_64__) -#define ARCH_CPU_X86_FAMILY 1 -#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) -#define ARCH_CPU_X86_FAMILY 1 -#elif defined(__ARMEL__) -#define ARCH_CPU_ARM_FAMILY 1 -#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) -#define ARCH_CPU_PPC_FAMILY 1 -#endif - -namespace leveldb { -namespace port { - -// Define MemoryBarrier() if available -// Windows on x86 -#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) -// windows.h already provides a MemoryBarrier(void) macro -// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx -#define LEVELDB_HAVE_MEMORY_BARRIER - -// Gcc on x86 -#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) -inline void MemoryBarrier() { - // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on - // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. - __asm__ __volatile__("" : : : "memory"); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// Sun Studio -#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) -inline void MemoryBarrier() { - // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on - // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. - asm volatile("" : : : "memory"); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// Mac OS -#elif defined(OS_MACOSX) -inline void MemoryBarrier() { - OSMemoryBarrier(); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// ARM Linux -#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) -typedef void (*LinuxKernelMemoryBarrierFunc)(void); -// The Linux ARM kernel provides a highly optimized device-specific memory -// barrier function at a fixed memory address that is mapped in every -// user-level process. -// -// This beats using CPU-specific instructions which are, on single-core -// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more -// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking -// shows that the extra function call cost is completely negligible on -// multi-core devices. -// -inline void MemoryBarrier() { - (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)(); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// PPC -#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) -inline void MemoryBarrier() { - // TODO for some powerpc expert: is there a cheaper suitable variant? - // Perhaps by having separate barriers for acquire and release ops. - asm volatile("sync" : : : "memory"); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -#endif - -// AtomicPointer built using platform-specific MemoryBarrier() -#if defined(LEVELDB_HAVE_MEMORY_BARRIER) -class AtomicPointer { - private: - void* rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* p) : rep_(p) {} - inline void* NoBarrier_Load() const { return rep_; } - inline void NoBarrier_Store(void* v) { rep_ = v; } - inline void* Acquire_Load() const { - void* result = rep_; - MemoryBarrier(); - return result; - } - inline void Release_Store(void* v) { - MemoryBarrier(); - rep_ = v; - } -}; - -// AtomicPointer based on -#elif defined(LEVELDB_CSTDATOMIC_PRESENT) -class AtomicPointer { - private: - std::atomic rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - return rep_.load(std::memory_order_acquire); - } - inline void Release_Store(void* v) { - rep_.store(v, std::memory_order_release); - } - inline void* NoBarrier_Load() const { - return rep_.load(std::memory_order_relaxed); - } - inline void NoBarrier_Store(void* v) { - rep_.store(v, std::memory_order_relaxed); - } -}; - -// Atomic pointer based on sparc memory barriers -#elif defined(__sparcv9) && defined(__GNUC__) -class AtomicPointer { - private: - void* rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - void* val; - __asm__ __volatile__ ( - "ldx [%[rep_]], %[val] \n\t" - "membar #LoadLoad|#LoadStore \n\t" - : [val] "=r" (val) - : [rep_] "r" (&rep_) - : "memory"); - return val; - } - inline void Release_Store(void* v) { - __asm__ __volatile__ ( - "membar #LoadStore|#StoreStore \n\t" - "stx %[v], [%[rep_]] \n\t" - : - : [rep_] "r" (&rep_), [v] "r" (v) - : "memory"); - } - inline void* NoBarrier_Load() const { return rep_; } - inline void NoBarrier_Store(void* v) { rep_ = v; } -}; - -// Atomic pointer based on ia64 acq/rel -#elif defined(__ia64) && defined(__GNUC__) -class AtomicPointer { - private: - void* rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - void* val ; - __asm__ __volatile__ ( - "ld8.acq %[val] = [%[rep_]] \n\t" - : [val] "=r" (val) - : [rep_] "r" (&rep_) - : "memory" - ); - return val; - } - inline void Release_Store(void* v) { - __asm__ __volatile__ ( - "st8.rel [%[rep_]] = %[v] \n\t" - : - : [rep_] "r" (&rep_), [v] "r" (v) - : "memory" - ); - } - inline void* NoBarrier_Load() const { return rep_; } - inline void NoBarrier_Store(void* v) { rep_ = v; } -}; - -// We have neither MemoryBarrier(), nor -#else -#error Please implement AtomicPointer for this platform. - -#endif - -#undef LEVELDB_HAVE_MEMORY_BARRIER -#undef ARCH_CPU_X86_FAMILY -#undef ARCH_CPU_ARM_FAMILY -#undef ARCH_CPU_PPC_FAMILY - -} // namespace port -} // namespace leveldb - -#endif // PORT_ATOMIC_POINTER_H_ diff --git a/src/leveldb/port/port.h b/src/leveldb/port/port.h deleted file mode 100644 index 4baafa8e2..000000000 --- a/src/leveldb/port/port.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_PORT_PORT_H_ -#define STORAGE_LEVELDB_PORT_PORT_H_ - -#include - -// Include the appropriate platform specific file below. If you are -// porting to a new platform, see "port_example.h" for documentation -// of what the new port_.h file must provide. -#if defined(LEVELDB_PLATFORM_POSIX) -# include "port/port_posix.h" -#elif defined(LEVELDB_PLATFORM_CHROMIUM) -# include "port/port_chromium.h" -#elif defined(LEVELDB_PLATFORM_WINDOWS) -# include "port/port_win.h" -#endif - -#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h deleted file mode 100644 index ab9e489b3..000000000 --- a/src/leveldb/port/port_example.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// This file contains the specification, but not the implementations, -// of the types/operations/etc. that should be defined by a platform -// specific port_.h file. Use this file as a reference for -// how to port this package to a new platform. - -#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ -#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ - -namespace leveldb { -namespace port { - -// TODO(jorlow): Many of these belong more in the environment class rather than -// here. We should try moving them and see if it affects perf. - -// The following boolean constant must be true on a little-endian machine -// and false otherwise. -static const bool kLittleEndian = true /* or some other expression */; - -// ------------------ Threading ------------------- - -// A Mutex represents an exclusive lock. -class Mutex { - public: - Mutex(); - ~Mutex(); - - // Lock the mutex. Waits until other lockers have exited. - // Will deadlock if the mutex is already locked by this thread. - void Lock(); - - // Unlock the mutex. - // REQUIRES: This mutex was locked by this thread. - void Unlock(); - - // Optionally crash if this thread does not hold this mutex. - // The implementation must be fast, especially if NDEBUG is - // defined. The implementation is allowed to skip all checks. - void AssertHeld(); -}; - -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - - // Atomically release *mu and block on this condition variable until - // either a call to SignalAll(), or a call to Signal() that picks - // this thread to wakeup. - // REQUIRES: this thread holds *mu - void Wait(); - - // If there are some threads waiting, wake up at least one of them. - void Signal(); - - // Wake up all waiting threads. - void SignallAll(); -}; - -// Thread-safe initialization. -// Used as follows: -// static port::OnceType init_control = LEVELDB_ONCE_INIT; -// static void Initializer() { ... do something ...; } -// ... -// port::InitOnce(&init_control, &Initializer); -typedef intptr_t OnceType; -#define LEVELDB_ONCE_INIT 0 -extern void InitOnce(port::OnceType*, void (*initializer)()); - -// A type that holds a pointer that can be read or written atomically -// (i.e., without word-tearing.) -class AtomicPointer { - private: - intptr_t rep_; - public: - // Initialize to arbitrary value - AtomicPointer(); - - // Initialize to hold v - explicit AtomicPointer(void* v) : rep_(v) { } - - // Read and return the stored pointer with the guarantee that no - // later memory access (read or write) by this thread can be - // reordered ahead of this read. - void* Acquire_Load() const; - - // Set v as the stored pointer with the guarantee that no earlier - // memory access (read or write) by this thread can be reordered - // after this store. - void Release_Store(void* v); - - // Read the stored pointer with no ordering guarantees. - void* NoBarrier_Load() const; - - // Set va as the stored pointer with no ordering guarantees. - void NoBarrier_Store(void* v); -}; - -// ------------------ Compression ------------------- - -// Store the snappy compression of "input[0,input_length-1]" in *output. -// Returns false if snappy is not supported by this port. -extern bool Snappy_Compress(const char* input, size_t input_length, - std::string* output); - -// If input[0,input_length-1] looks like a valid snappy compressed -// buffer, store the size of the uncompressed data in *result and -// return true. Else return false. -extern bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result); - -// Attempt to snappy uncompress input[0,input_length-1] into *output. -// Returns true if successful, false if the input is invalid lightweight -// compressed data. -// -// REQUIRES: at least the first "n" bytes of output[] must be writable -// where "n" is the result of a successful call to -// Snappy_GetUncompressedLength. -extern bool Snappy_Uncompress(const char* input_data, size_t input_length, - char* output); - -// ------------------ Miscellaneous ------------------- - -// If heap profiling is not supported, returns false. -// Else repeatedly calls (*func)(arg, data, n) and then returns true. -// The concatenation of all "data[0,n-1]" fragments is the heap profile. -extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); - -} // namespace port -} // namespace leveldb - -#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc deleted file mode 100644 index 5ba127a5b..000000000 --- a/src/leveldb/port/port_posix.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "port/port_posix.h" - -#include -#include -#include -#include "util/logging.h" - -namespace leveldb { -namespace port { - -static void PthreadCall(const char* label, int result) { - if (result != 0) { - fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - abort(); - } -} - -Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); } - -Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } - -void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } - -void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } - -CondVar::CondVar(Mutex* mu) - : mu_(mu) { - PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); -} - -CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } - -void CondVar::Wait() { - PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); -} - -void CondVar::Signal() { - PthreadCall("signal", pthread_cond_signal(&cv_)); -} - -void CondVar::SignalAll() { - PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); -} - -void InitOnce(OnceType* once, void (*initializer)()) { - PthreadCall("once", pthread_once(once, initializer)); -} - -} // namespace port -} // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h deleted file mode 100644 index f2b89bffb..000000000 --- a/src/leveldb/port/port_posix.h +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ -#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ - -#undef PLATFORM_IS_LITTLE_ENDIAN -#if defined(OS_MACOSX) - #include - #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER) - #define PLATFORM_IS_LITTLE_ENDIAN \ - (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN) - #endif -#elif defined(OS_SOLARIS) - #include - #ifdef _LITTLE_ENDIAN - #define PLATFORM_IS_LITTLE_ENDIAN true - #else - #define PLATFORM_IS_LITTLE_ENDIAN false - #endif -#elif defined(OS_FREEBSD) - #include - #include - #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) -#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\ - defined(OS_DRAGONFLYBSD) - #include - #include -#elif defined(OS_HPUX) - #define PLATFORM_IS_LITTLE_ENDIAN false -#elif defined(OS_ANDROID) - // Due to a bug in the NDK x86 definition, - // _BYTE_ORDER must be used instead of __BYTE_ORDER on Android. - // See http://code.google.com/p/android/issues/detail?id=39824 - #include - #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) -#else - #include -#endif - -#include -#ifdef SNAPPY -#include -#endif -#include -#include -#include "port/atomic_pointer.h" - -#ifndef PLATFORM_IS_LITTLE_ENDIAN -#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) -#endif - -#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ - defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ - defined(OS_ANDROID) || defined(OS_HPUX) -// Use fread/fwrite/fflush on platforms without _unlocked variants -#define fread_unlocked fread -#define fwrite_unlocked fwrite -#define fflush_unlocked fflush -#endif - -#if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\ - defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) -// Use fsync() on platforms without fdatasync() -#define fdatasync fsync -#endif - -#if defined(OS_ANDROID) && __ANDROID_API__ < 9 -// fdatasync() was only introduced in API level 9 on Android. Use fsync() -// when targetting older platforms. -#define fdatasync fsync -#endif - -namespace leveldb { -namespace port { - -static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN; -#undef PLATFORM_IS_LITTLE_ENDIAN - -class CondVar; - -class Mutex { - public: - Mutex(); - ~Mutex(); - - void Lock(); - void Unlock(); - void AssertHeld() { } - - private: - friend class CondVar; - pthread_mutex_t mu_; - - // No copying - Mutex(const Mutex&); - void operator=(const Mutex&); -}; - -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - void Wait(); - void Signal(); - void SignalAll(); - private: - pthread_cond_t cv_; - Mutex* mu_; -}; - -typedef pthread_once_t OnceType; -#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT -extern void InitOnce(OnceType* once, void (*initializer)()); - -inline bool Snappy_Compress(const char* input, size_t length, - ::std::string* output) { -#ifdef SNAPPY - output->resize(snappy::MaxCompressedLength(length)); - size_t outlen; - snappy::RawCompress(input, length, &(*output)[0], &outlen); - output->resize(outlen); - return true; -#endif - - return false; -} - -inline bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result) { -#ifdef SNAPPY - return snappy::GetUncompressedLength(input, length, result); -#else - return false; -#endif -} - -inline bool Snappy_Uncompress(const char* input, size_t length, - char* output) { -#ifdef SNAPPY - return snappy::RawUncompress(input, length, output); -#else - return false; -#endif -} - -inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { - return false; -} - -} // namespace port -} // namespace leveldb - -#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc deleted file mode 100644 index 99c1d8e34..000000000 --- a/src/leveldb/port/port_win.cc +++ /dev/null @@ -1,149 +0,0 @@ -// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the University of California, Berkeley nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#include "port/port_win.h" - -#include -#include - -namespace leveldb { -namespace port { - -Mutex::Mutex() : - cs_(NULL) { - assert(!cs_); - cs_ = static_cast(new CRITICAL_SECTION()); - ::InitializeCriticalSection(static_cast(cs_)); - assert(cs_); -} - -Mutex::~Mutex() { - assert(cs_); - ::DeleteCriticalSection(static_cast(cs_)); - delete static_cast(cs_); - cs_ = NULL; - assert(!cs_); -} - -void Mutex::Lock() { - assert(cs_); - ::EnterCriticalSection(static_cast(cs_)); -} - -void Mutex::Unlock() { - assert(cs_); - ::LeaveCriticalSection(static_cast(cs_)); -} - -void Mutex::AssertHeld() { - assert(cs_); - assert(1); -} - -CondVar::CondVar(Mutex* mu) : - waiting_(0), - mu_(mu), - sem1_(::CreateSemaphore(NULL, 0, 10000, NULL)), - sem2_(::CreateSemaphore(NULL, 0, 10000, NULL)) { - assert(mu_); -} - -CondVar::~CondVar() { - ::CloseHandle(sem1_); - ::CloseHandle(sem2_); -} - -void CondVar::Wait() { - mu_->AssertHeld(); - - wait_mtx_.Lock(); - ++waiting_; - wait_mtx_.Unlock(); - - mu_->Unlock(); - - // initiate handshake - ::WaitForSingleObject(sem1_, INFINITE); - ::ReleaseSemaphore(sem2_, 1, NULL); - mu_->Lock(); -} - -void CondVar::Signal() { - wait_mtx_.Lock(); - if (waiting_ > 0) { - --waiting_; - - // finalize handshake - ::ReleaseSemaphore(sem1_, 1, NULL); - ::WaitForSingleObject(sem2_, INFINITE); - } - wait_mtx_.Unlock(); -} - -void CondVar::SignalAll() { - wait_mtx_.Lock(); - for(long i = 0; i < waiting_; ++i) { - ::ReleaseSemaphore(sem1_, 1, NULL); - while(waiting_ > 0) { - --waiting_; - ::WaitForSingleObject(sem2_, INFINITE); - } - } - wait_mtx_.Unlock(); -} - -AtomicPointer::AtomicPointer(void* v) { - Release_Store(v); -} - -void InitOnce(OnceType* once, void (*initializer)()) { - once->InitOnce(initializer); -} - -void* AtomicPointer::Acquire_Load() const { - void * p = NULL; - InterlockedExchangePointer(&p, rep_); - return p; -} - -void AtomicPointer::Release_Store(void* v) { - InterlockedExchangePointer(&rep_, v); -} - -void* AtomicPointer::NoBarrier_Load() const { - return rep_; -} - -void AtomicPointer::NoBarrier_Store(void* v) { - rep_ = v; -} - -} -} diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h deleted file mode 100644 index 45bf2f0ea..000000000 --- a/src/leveldb/port/port_win.h +++ /dev/null @@ -1,174 +0,0 @@ -// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the University of California, Berkeley nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ -#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ - -#ifdef _MSC_VER -#define snprintf _snprintf -#define close _close -#define fread_unlocked _fread_nolock -#endif - -#include -#include -#ifdef SNAPPY -#include -#endif - -namespace leveldb { -namespace port { - -// Windows is little endian (for now :p) -static const bool kLittleEndian = true; - -class CondVar; - -class Mutex { - public: - Mutex(); - ~Mutex(); - - void Lock(); - void Unlock(); - void AssertHeld(); - - private: - friend class CondVar; - // critical sections are more efficient than mutexes - // but they are not recursive and can only be used to synchronize threads within the same process - // we use opaque void * to avoid including windows.h in port_win.h - void * cs_; - - // No copying - Mutex(const Mutex&); - void operator=(const Mutex&); -}; - -// the Win32 API offers a dependable condition variable mechanism, but only starting with -// Windows 2008 and Vista -// no matter what we will implement our own condition variable with a semaphore -// implementation as described in a paper written by Andrew D. Birrell in 2003 -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - void Wait(); - void Signal(); - void SignalAll(); - private: - Mutex* mu_; - - Mutex wait_mtx_; - long waiting_; - - void * sem1_; - void * sem2_; - - -}; - -class OnceType { -public: -// OnceType() : init_(false) {} - OnceType(const OnceType &once) : init_(once.init_) {} - OnceType(bool f) : init_(f) {} - void InitOnce(void (*initializer)()) { - mutex_.Lock(); - if (!init_) { - init_ = true; - initializer(); - } - mutex_.Unlock(); - } - -private: - bool init_; - Mutex mutex_; -}; - -#define LEVELDB_ONCE_INIT false -extern void InitOnce(port::OnceType*, void (*initializer)()); - -// Storage for a lock-free pointer -class AtomicPointer { - private: - void * rep_; - public: - AtomicPointer() : rep_(NULL) { } - explicit AtomicPointer(void* v); - void* Acquire_Load() const; - - void Release_Store(void* v); - - void* NoBarrier_Load() const; - - void NoBarrier_Store(void* v); -}; - -inline bool Snappy_Compress(const char* input, size_t length, - ::std::string* output) { -#ifdef SNAPPY - output->resize(snappy::MaxCompressedLength(length)); - size_t outlen; - snappy::RawCompress(input, length, &(*output)[0], &outlen); - output->resize(outlen); - return true; -#endif - - return false; -} - -inline bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result) { -#ifdef SNAPPY - return snappy::GetUncompressedLength(input, length, result); -#else - return false; -#endif -} - -inline bool Snappy_Uncompress(const char* input, size_t length, - char* output) { -#ifdef SNAPPY - return snappy::RawUncompress(input, length, output); -#else - return false; -#endif -} - -inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { - return false; -} - -} -} - -#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ diff --git a/src/leveldb/port/thread_annotations.h b/src/leveldb/port/thread_annotations.h deleted file mode 100644 index 6f9b6a792..000000000 --- a/src/leveldb/port/thread_annotations.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H - -// Some environments provide custom macros to aid in static thread-safety -// analysis. Provide empty definitions of such macros unless they are already -// defined. - -#ifndef EXCLUSIVE_LOCKS_REQUIRED -#define EXCLUSIVE_LOCKS_REQUIRED(...) -#endif - -#ifndef SHARED_LOCKS_REQUIRED -#define SHARED_LOCKS_REQUIRED(...) -#endif - -#ifndef LOCKS_EXCLUDED -#define LOCKS_EXCLUDED(...) -#endif - -#ifndef LOCK_RETURNED -#define LOCK_RETURNED(x) -#endif - -#ifndef LOCKABLE -#define LOCKABLE -#endif - -#ifndef SCOPED_LOCKABLE -#define SCOPED_LOCKABLE -#endif - -#ifndef EXCLUSIVE_LOCK_FUNCTION -#define EXCLUSIVE_LOCK_FUNCTION(...) -#endif - -#ifndef SHARED_LOCK_FUNCTION -#define SHARED_LOCK_FUNCTION(...) -#endif - -#ifndef EXCLUSIVE_TRYLOCK_FUNCTION -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) -#endif - -#ifndef SHARED_TRYLOCK_FUNCTION -#define SHARED_TRYLOCK_FUNCTION(...) -#endif - -#ifndef UNLOCK_FUNCTION -#define UNLOCK_FUNCTION(...) -#endif - -#ifndef NO_THREAD_SAFETY_ANALYSIS -#define NO_THREAD_SAFETY_ANALYSIS -#endif - -#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H diff --git a/src/leveldb/port/win/stdint.h b/src/leveldb/port/win/stdint.h deleted file mode 100644 index 39edd0db1..000000000 --- a/src/leveldb/port/win/stdint.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// MSVC didn't ship with this file until the 2010 version. - -#ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_ -#define STORAGE_LEVELDB_PORT_WIN_STDINT_H_ - -#if !defined(_MSC_VER) -#error This file should only be included when compiling with MSVC. -#endif - -// Define C99 equivalent types. -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed long long int64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; - -#endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_ diff --git a/src/leveldb/table/block.cc b/src/leveldb/table/block.cc deleted file mode 100644 index ab83c1112..000000000 --- a/src/leveldb/table/block.cc +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Decodes the blocks generated by block_builder.cc. - -#include "table/block.h" - -#include -#include -#include "leveldb/comparator.h" -#include "table/format.h" -#include "util/coding.h" -#include "util/logging.h" - -namespace leveldb { - -inline uint32_t Block::NumRestarts() const { - assert(size_ >= 2*sizeof(uint32_t)); - return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); -} - -Block::Block(const BlockContents& contents) - : data_(contents.data.data()), - size_(contents.data.size()), - owned_(contents.heap_allocated) { - if (size_ < sizeof(uint32_t)) { - size_ = 0; // Error marker - } else { - restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); - if (restart_offset_ > size_ - sizeof(uint32_t)) { - // The size is too small for NumRestarts() and therefore - // restart_offset_ wrapped around. - size_ = 0; - } - } -} - -Block::~Block() { - if (owned_) { - delete[] data_; - } -} - -// Helper routine: decode the next block entry starting at "p", -// storing the number of shared key bytes, non_shared key bytes, -// and the length of the value in "*shared", "*non_shared", and -// "*value_length", respectively. Will not derefence past "limit". -// -// If any errors are detected, returns NULL. Otherwise, returns a -// pointer to the key delta (just past the three decoded values). -static inline const char* DecodeEntry(const char* p, const char* limit, - uint32_t* shared, - uint32_t* non_shared, - uint32_t* value_length) { - if (limit - p < 3) return NULL; - *shared = reinterpret_cast(p)[0]; - *non_shared = reinterpret_cast(p)[1]; - *value_length = reinterpret_cast(p)[2]; - if ((*shared | *non_shared | *value_length) < 128) { - // Fast path: all three values are encoded in one byte each - p += 3; - } else { - if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL; - if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL; - if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL; - } - - if (static_cast(limit - p) < (*non_shared + *value_length)) { - return NULL; - } - return p; -} - -class Block::Iter : public Iterator { - private: - const Comparator* const comparator_; - const char* const data_; // underlying block contents - uint32_t const restarts_; // Offset of restart array (list of fixed32) - uint32_t const num_restarts_; // Number of uint32_t entries in restart array - - // current_ is offset in data_ of current entry. >= restarts_ if !Valid - uint32_t current_; - uint32_t restart_index_; // Index of restart block in which current_ falls - std::string key_; - Slice value_; - Status status_; - - inline int Compare(const Slice& a, const Slice& b) const { - return comparator_->Compare(a, b); - } - - // Return the offset in data_ just past the end of the current entry. - inline uint32_t NextEntryOffset() const { - return (value_.data() + value_.size()) - data_; - } - - uint32_t GetRestartPoint(uint32_t index) { - assert(index < num_restarts_); - return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); - } - - void SeekToRestartPoint(uint32_t index) { - key_.clear(); - restart_index_ = index; - // current_ will be fixed by ParseNextKey(); - - // ParseNextKey() starts at the end of value_, so set value_ accordingly - uint32_t offset = GetRestartPoint(index); - value_ = Slice(data_ + offset, 0); - } - - public: - Iter(const Comparator* comparator, - const char* data, - uint32_t restarts, - uint32_t num_restarts) - : comparator_(comparator), - data_(data), - restarts_(restarts), - num_restarts_(num_restarts), - current_(restarts_), - restart_index_(num_restarts_) { - assert(num_restarts_ > 0); - } - - virtual bool Valid() const { return current_ < restarts_; } - virtual Status status() const { return status_; } - virtual Slice key() const { - assert(Valid()); - return key_; - } - virtual Slice value() const { - assert(Valid()); - return value_; - } - - virtual void Next() { - assert(Valid()); - ParseNextKey(); - } - - virtual void Prev() { - assert(Valid()); - - // Scan backwards to a restart point before current_ - const uint32_t original = current_; - while (GetRestartPoint(restart_index_) >= original) { - if (restart_index_ == 0) { - // No more entries - current_ = restarts_; - restart_index_ = num_restarts_; - return; - } - restart_index_--; - } - - SeekToRestartPoint(restart_index_); - do { - // Loop until end of current entry hits the start of original entry - } while (ParseNextKey() && NextEntryOffset() < original); - } - - virtual void Seek(const Slice& target) { - // Binary search in restart array to find the last restart point - // with a key < target - uint32_t left = 0; - uint32_t right = num_restarts_ - 1; - while (left < right) { - uint32_t mid = (left + right + 1) / 2; - uint32_t region_offset = GetRestartPoint(mid); - uint32_t shared, non_shared, value_length; - const char* key_ptr = DecodeEntry(data_ + region_offset, - data_ + restarts_, - &shared, &non_shared, &value_length); - if (key_ptr == NULL || (shared != 0)) { - CorruptionError(); - return; - } - Slice mid_key(key_ptr, non_shared); - if (Compare(mid_key, target) < 0) { - // Key at "mid" is smaller than "target". Therefore all - // blocks before "mid" are uninteresting. - left = mid; - } else { - // Key at "mid" is >= "target". Therefore all blocks at or - // after "mid" are uninteresting. - right = mid - 1; - } - } - - // Linear search (within restart block) for first key >= target - SeekToRestartPoint(left); - while (true) { - if (!ParseNextKey()) { - return; - } - if (Compare(key_, target) >= 0) { - return; - } - } - } - - virtual void SeekToFirst() { - SeekToRestartPoint(0); - ParseNextKey(); - } - - virtual void SeekToLast() { - SeekToRestartPoint(num_restarts_ - 1); - while (ParseNextKey() && NextEntryOffset() < restarts_) { - // Keep skipping - } - } - - private: - void CorruptionError() { - current_ = restarts_; - restart_index_ = num_restarts_; - status_ = Status::Corruption("bad entry in block"); - key_.clear(); - value_.clear(); - } - - bool ParseNextKey() { - current_ = NextEntryOffset(); - const char* p = data_ + current_; - const char* limit = data_ + restarts_; // Restarts come right after data - if (p >= limit) { - // No more entries to return. Mark as invalid. - current_ = restarts_; - restart_index_ = num_restarts_; - return false; - } - - // Decode next entry - uint32_t shared, non_shared, value_length; - p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); - if (p == NULL || key_.size() < shared) { - CorruptionError(); - return false; - } else { - key_.resize(shared); - key_.append(p, non_shared); - value_ = Slice(p + non_shared, value_length); - while (restart_index_ + 1 < num_restarts_ && - GetRestartPoint(restart_index_ + 1) < current_) { - ++restart_index_; - } - return true; - } - } -}; - -Iterator* Block::NewIterator(const Comparator* cmp) { - if (size_ < 2*sizeof(uint32_t)) { - return NewErrorIterator(Status::Corruption("bad block contents")); - } - const uint32_t num_restarts = NumRestarts(); - if (num_restarts == 0) { - return NewEmptyIterator(); - } else { - return new Iter(cmp, data_, restart_offset_, num_restarts); - } -} - -} // namespace leveldb diff --git a/src/leveldb/table/block.h b/src/leveldb/table/block.h deleted file mode 100644 index 2493eb9f9..000000000 --- a/src/leveldb/table/block.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_ -#define STORAGE_LEVELDB_TABLE_BLOCK_H_ - -#include -#include -#include "leveldb/iterator.h" - -namespace leveldb { - -struct BlockContents; -class Comparator; - -class Block { - public: - // Initialize the block with the specified contents. - explicit Block(const BlockContents& contents); - - ~Block(); - - size_t size() const { return size_; } - Iterator* NewIterator(const Comparator* comparator); - - private: - uint32_t NumRestarts() const; - - const char* data_; - size_t size_; - uint32_t restart_offset_; // Offset in data_ of restart array - bool owned_; // Block owns data_[] - - // No copying allowed - Block(const Block&); - void operator=(const Block&); - - class Iter; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/src/leveldb/table/block_builder.cc b/src/leveldb/table/block_builder.cc deleted file mode 100644 index db660cd07..000000000 --- a/src/leveldb/table/block_builder.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// BlockBuilder generates blocks where keys are prefix-compressed: -// -// When we store a key, we drop the prefix shared with the previous -// string. This helps reduce the space requirement significantly. -// Furthermore, once every K keys, we do not apply the prefix -// compression and store the entire key. We call this a "restart -// point". The tail end of the block stores the offsets of all of the -// restart points, and can be used to do a binary search when looking -// for a particular key. Values are stored as-is (without compression) -// immediately following the corresponding key. -// -// An entry for a particular key-value pair has the form: -// shared_bytes: varint32 -// unshared_bytes: varint32 -// value_length: varint32 -// key_delta: char[unshared_bytes] -// value: char[value_length] -// shared_bytes == 0 for restart points. -// -// The trailer of the block has the form: -// restarts: uint32[num_restarts] -// num_restarts: uint32 -// restarts[i] contains the offset within the block of the ith restart point. - -#include "table/block_builder.h" - -#include -#include -#include "leveldb/comparator.h" -#include "leveldb/table_builder.h" -#include "util/coding.h" - -namespace leveldb { - -BlockBuilder::BlockBuilder(const Options* options) - : options_(options), - restarts_(), - counter_(0), - finished_(false) { - assert(options->block_restart_interval >= 1); - restarts_.push_back(0); // First restart point is at offset 0 -} - -void BlockBuilder::Reset() { - buffer_.clear(); - restarts_.clear(); - restarts_.push_back(0); // First restart point is at offset 0 - counter_ = 0; - finished_ = false; - last_key_.clear(); -} - -size_t BlockBuilder::CurrentSizeEstimate() const { - return (buffer_.size() + // Raw data buffer - restarts_.size() * sizeof(uint32_t) + // Restart array - sizeof(uint32_t)); // Restart array length -} - -Slice BlockBuilder::Finish() { - // Append restart array - for (size_t i = 0; i < restarts_.size(); i++) { - PutFixed32(&buffer_, restarts_[i]); - } - PutFixed32(&buffer_, restarts_.size()); - finished_ = true; - return Slice(buffer_); -} - -void BlockBuilder::Add(const Slice& key, const Slice& value) { - Slice last_key_piece(last_key_); - assert(!finished_); - assert(counter_ <= options_->block_restart_interval); - assert(buffer_.empty() // No values yet? - || options_->comparator->Compare(key, last_key_piece) > 0); - size_t shared = 0; - if (counter_ < options_->block_restart_interval) { - // See how much sharing to do with previous string - const size_t min_length = std::min(last_key_piece.size(), key.size()); - while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { - shared++; - } - } else { - // Restart compression - restarts_.push_back(buffer_.size()); - counter_ = 0; - } - const size_t non_shared = key.size() - shared; - - // Add "" to buffer_ - PutVarint32(&buffer_, shared); - PutVarint32(&buffer_, non_shared); - PutVarint32(&buffer_, value.size()); - - // Add string delta to buffer_ followed by value - buffer_.append(key.data() + shared, non_shared); - buffer_.append(value.data(), value.size()); - - // Update state - last_key_.resize(shared); - last_key_.append(key.data() + shared, non_shared); - assert(Slice(last_key_) == key); - counter_++; -} - -} // namespace leveldb diff --git a/src/leveldb/table/block_builder.h b/src/leveldb/table/block_builder.h deleted file mode 100644 index 5b545bd1a..000000000 --- a/src/leveldb/table/block_builder.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ -#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ - -#include - -#include -#include "leveldb/slice.h" - -namespace leveldb { - -struct Options; - -class BlockBuilder { - public: - explicit BlockBuilder(const Options* options); - - // Reset the contents as if the BlockBuilder was just constructed. - void Reset(); - - // REQUIRES: Finish() has not been callled since the last call to Reset(). - // REQUIRES: key is larger than any previously added key - void Add(const Slice& key, const Slice& value); - - // Finish building the block and return a slice that refers to the - // block contents. The returned slice will remain valid for the - // lifetime of this builder or until Reset() is called. - Slice Finish(); - - // Returns an estimate of the current (uncompressed) size of the block - // we are building. - size_t CurrentSizeEstimate() const; - - // Return true iff no entries have been added since the last Reset() - bool empty() const { - return buffer_.empty(); - } - - private: - const Options* options_; - std::string buffer_; // Destination buffer - std::vector restarts_; // Restart points - int counter_; // Number of entries emitted since restart - bool finished_; // Has Finish() been called? - std::string last_key_; - - // No copying allowed - BlockBuilder(const BlockBuilder&); - void operator=(const BlockBuilder&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/src/leveldb/table/filter_block.cc b/src/leveldb/table/filter_block.cc deleted file mode 100644 index 203e15c8b..000000000 --- a/src/leveldb/table/filter_block.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/filter_block.h" - -#include "leveldb/filter_policy.h" -#include "util/coding.h" - -namespace leveldb { - -// See doc/table_format.txt for an explanation of the filter block format. - -// Generate new filter every 2KB of data -static const size_t kFilterBaseLg = 11; -static const size_t kFilterBase = 1 << kFilterBaseLg; - -FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) - : policy_(policy) { -} - -void FilterBlockBuilder::StartBlock(uint64_t block_offset) { - uint64_t filter_index = (block_offset / kFilterBase); - assert(filter_index >= filter_offsets_.size()); - while (filter_index > filter_offsets_.size()) { - GenerateFilter(); - } -} - -void FilterBlockBuilder::AddKey(const Slice& key) { - Slice k = key; - start_.push_back(keys_.size()); - keys_.append(k.data(), k.size()); -} - -Slice FilterBlockBuilder::Finish() { - if (!start_.empty()) { - GenerateFilter(); - } - - // Append array of per-filter offsets - const uint32_t array_offset = result_.size(); - for (size_t i = 0; i < filter_offsets_.size(); i++) { - PutFixed32(&result_, filter_offsets_[i]); - } - - PutFixed32(&result_, array_offset); - result_.push_back(kFilterBaseLg); // Save encoding parameter in result - return Slice(result_); -} - -void FilterBlockBuilder::GenerateFilter() { - const size_t num_keys = start_.size(); - if (num_keys == 0) { - // Fast path if there are no keys for this filter - filter_offsets_.push_back(result_.size()); - return; - } - - // Make list of keys from flattened key structure - start_.push_back(keys_.size()); // Simplify length computation - tmp_keys_.resize(num_keys); - for (size_t i = 0; i < num_keys; i++) { - const char* base = keys_.data() + start_[i]; - size_t length = start_[i+1] - start_[i]; - tmp_keys_[i] = Slice(base, length); - } - - // Generate filter for current set of keys and append to result_. - filter_offsets_.push_back(result_.size()); - policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_); - - tmp_keys_.clear(); - keys_.clear(); - start_.clear(); -} - -FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, - const Slice& contents) - : policy_(policy), - data_(NULL), - offset_(NULL), - num_(0), - base_lg_(0) { - size_t n = contents.size(); - if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array - base_lg_ = contents[n-1]; - uint32_t last_word = DecodeFixed32(contents.data() + n - 5); - if (last_word > n - 5) return; - data_ = contents.data(); - offset_ = data_ + last_word; - num_ = (n - 5 - last_word) / 4; -} - -bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { - uint64_t index = block_offset >> base_lg_; - if (index < num_) { - uint32_t start = DecodeFixed32(offset_ + index*4); - uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); - if (start <= limit && limit <= (offset_ - data_)) { - Slice filter = Slice(data_ + start, limit - start); - return policy_->KeyMayMatch(key, filter); - } else if (start == limit) { - // Empty filters do not match any keys - return false; - } - } - return true; // Errors are treated as potential matches -} - -} diff --git a/src/leveldb/table/filter_block.h b/src/leveldb/table/filter_block.h deleted file mode 100644 index c67d010bd..000000000 --- a/src/leveldb/table/filter_block.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A filter block is stored near the end of a Table file. It contains -// filters (e.g., bloom filters) for all data blocks in the table combined -// into a single filter block. - -#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ -#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ - -#include -#include -#include -#include -#include "leveldb/slice.h" -#include "util/hash.h" - -namespace leveldb { - -class FilterPolicy; - -// A FilterBlockBuilder is used to construct all of the filters for a -// particular Table. It generates a single string which is stored as -// a special block in the Table. -// -// The sequence of calls to FilterBlockBuilder must match the regexp: -// (StartBlock AddKey*)* Finish -class FilterBlockBuilder { - public: - explicit FilterBlockBuilder(const FilterPolicy*); - - void StartBlock(uint64_t block_offset); - void AddKey(const Slice& key); - Slice Finish(); - - private: - void GenerateFilter(); - - const FilterPolicy* policy_; - std::string keys_; // Flattened key contents - std::vector start_; // Starting index in keys_ of each key - std::string result_; // Filter data computed so far - std::vector tmp_keys_; // policy_->CreateFilter() argument - std::vector filter_offsets_; - - // No copying allowed - FilterBlockBuilder(const FilterBlockBuilder&); - void operator=(const FilterBlockBuilder&); -}; - -class FilterBlockReader { - public: - // REQUIRES: "contents" and *policy must stay live while *this is live. - FilterBlockReader(const FilterPolicy* policy, const Slice& contents); - bool KeyMayMatch(uint64_t block_offset, const Slice& key); - - private: - const FilterPolicy* policy_; - const char* data_; // Pointer to filter data (at block-start) - const char* offset_; // Pointer to beginning of offset array (at block-end) - size_t num_; // Number of entries in offset array - size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) -}; - -} - -#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/src/leveldb/table/filter_block_test.cc b/src/leveldb/table/filter_block_test.cc deleted file mode 100644 index 3a2a07cf5..000000000 --- a/src/leveldb/table/filter_block_test.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/filter_block.h" - -#include "leveldb/filter_policy.h" -#include "util/coding.h" -#include "util/hash.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -// For testing: emit an array with one hash value per key -class TestHashFilter : public FilterPolicy { - public: - virtual const char* Name() const { - return "TestHashFilter"; - } - - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { - for (int i = 0; i < n; i++) { - uint32_t h = Hash(keys[i].data(), keys[i].size(), 1); - PutFixed32(dst, h); - } - } - - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { - uint32_t h = Hash(key.data(), key.size(), 1); - for (int i = 0; i + 4 <= filter.size(); i += 4) { - if (h == DecodeFixed32(filter.data() + i)) { - return true; - } - } - return false; - } -}; - -class FilterBlockTest { - public: - TestHashFilter policy_; -}; - -TEST(FilterBlockTest, EmptyBuilder) { - FilterBlockBuilder builder(&policy_); - Slice block = builder.Finish(); - ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block)); - FilterBlockReader reader(&policy_, block); - ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); - ASSERT_TRUE(reader.KeyMayMatch(100000, "foo")); -} - -TEST(FilterBlockTest, SingleChunk) { - FilterBlockBuilder builder(&policy_); - builder.StartBlock(100); - builder.AddKey("foo"); - builder.AddKey("bar"); - builder.AddKey("box"); - builder.StartBlock(200); - builder.AddKey("box"); - builder.StartBlock(300); - builder.AddKey("hello"); - Slice block = builder.Finish(); - FilterBlockReader reader(&policy_, block); - ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); - ASSERT_TRUE(reader.KeyMayMatch(100, "bar")); - ASSERT_TRUE(reader.KeyMayMatch(100, "box")); - ASSERT_TRUE(reader.KeyMayMatch(100, "hello")); - ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(100, "missing")); - ASSERT_TRUE(! reader.KeyMayMatch(100, "other")); -} - -TEST(FilterBlockTest, MultiChunk) { - FilterBlockBuilder builder(&policy_); - - // First filter - builder.StartBlock(0); - builder.AddKey("foo"); - builder.StartBlock(2000); - builder.AddKey("bar"); - - // Second filter - builder.StartBlock(3100); - builder.AddKey("box"); - - // Third filter is empty - - // Last filter - builder.StartBlock(9000); - builder.AddKey("box"); - builder.AddKey("hello"); - - Slice block = builder.Finish(); - FilterBlockReader reader(&policy_, block); - - // Check first filter - ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); - ASSERT_TRUE(reader.KeyMayMatch(2000, "bar")); - ASSERT_TRUE(! reader.KeyMayMatch(0, "box")); - ASSERT_TRUE(! reader.KeyMayMatch(0, "hello")); - - // Check second filter - ASSERT_TRUE(reader.KeyMayMatch(3100, "box")); - ASSERT_TRUE(! reader.KeyMayMatch(3100, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(3100, "bar")); - ASSERT_TRUE(! reader.KeyMayMatch(3100, "hello")); - - // Check third filter (empty) - ASSERT_TRUE(! reader.KeyMayMatch(4100, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(4100, "bar")); - ASSERT_TRUE(! reader.KeyMayMatch(4100, "box")); - ASSERT_TRUE(! reader.KeyMayMatch(4100, "hello")); - - // Check last filter - ASSERT_TRUE(reader.KeyMayMatch(9000, "box")); - ASSERT_TRUE(reader.KeyMayMatch(9000, "hello")); - ASSERT_TRUE(! reader.KeyMayMatch(9000, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(9000, "bar")); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc deleted file mode 100644 index cda1decdf..000000000 --- a/src/leveldb/table/format.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/format.h" - -#include "leveldb/env.h" -#include "port/port.h" -#include "table/block.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { - -void BlockHandle::EncodeTo(std::string* dst) const { - // Sanity check that all fields have been set - assert(offset_ != ~static_cast(0)); - assert(size_ != ~static_cast(0)); - PutVarint64(dst, offset_); - PutVarint64(dst, size_); -} - -Status BlockHandle::DecodeFrom(Slice* input) { - if (GetVarint64(input, &offset_) && - GetVarint64(input, &size_)) { - return Status::OK(); - } else { - return Status::Corruption("bad block handle"); - } -} - -void Footer::EncodeTo(std::string* dst) const { -#ifndef NDEBUG - const size_t original_size = dst->size(); -#endif - metaindex_handle_.EncodeTo(dst); - index_handle_.EncodeTo(dst); - dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding - PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); - PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); - assert(dst->size() == original_size + kEncodedLength); -} - -Status Footer::DecodeFrom(Slice* input) { - const char* magic_ptr = input->data() + kEncodedLength - 8; - const uint32_t magic_lo = DecodeFixed32(magic_ptr); - const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); - const uint64_t magic = ((static_cast(magic_hi) << 32) | - (static_cast(magic_lo))); - if (magic != kTableMagicNumber) { - return Status::InvalidArgument("not an sstable (bad magic number)"); - } - - Status result = metaindex_handle_.DecodeFrom(input); - if (result.ok()) { - result = index_handle_.DecodeFrom(input); - } - if (result.ok()) { - // We skip over any leftover data (just padding for now) in "input" - const char* end = magic_ptr + 8; - *input = Slice(end, input->data() + input->size() - end); - } - return result; -} - -Status ReadBlock(RandomAccessFile* file, - const ReadOptions& options, - const BlockHandle& handle, - BlockContents* result) { - result->data = Slice(); - result->cachable = false; - result->heap_allocated = false; - - // Read the block contents as well as the type/crc footer. - // See table_builder.cc for the code that built this structure. - size_t n = static_cast(handle.size()); - char* buf = new char[n + kBlockTrailerSize]; - Slice contents; - Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); - if (!s.ok()) { - delete[] buf; - return s; - } - if (contents.size() != n + kBlockTrailerSize) { - delete[] buf; - return Status::Corruption("truncated block read"); - } - - // Check the crc of the type and the block contents - const char* data = contents.data(); // Pointer to where Read put the data - if (options.verify_checksums) { - const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); - const uint32_t actual = crc32c::Value(data, n + 1); - if (actual != crc) { - delete[] buf; - s = Status::Corruption("block checksum mismatch"); - return s; - } - } - - switch (data[n]) { - case kNoCompression: - if (data != buf) { - // File implementation gave us pointer to some other data. - // Use it directly under the assumption that it will be live - // while the file is open. - delete[] buf; - result->data = Slice(data, n); - result->heap_allocated = false; - result->cachable = false; // Do not double-cache - } else { - result->data = Slice(buf, n); - result->heap_allocated = true; - result->cachable = true; - } - - // Ok - break; - case kSnappyCompression: { - size_t ulength = 0; - if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { - delete[] buf; - return Status::Corruption("corrupted compressed block contents"); - } - char* ubuf = new char[ulength]; - if (!port::Snappy_Uncompress(data, n, ubuf)) { - delete[] buf; - delete[] ubuf; - return Status::Corruption("corrupted compressed block contents"); - } - delete[] buf; - result->data = Slice(ubuf, ulength); - result->heap_allocated = true; - result->cachable = true; - break; - } - default: - delete[] buf; - return Status::Corruption("bad block type"); - } - - return Status::OK(); -} - -} // namespace leveldb diff --git a/src/leveldb/table/format.h b/src/leveldb/table/format.h deleted file mode 100644 index 6c0b80c01..000000000 --- a/src/leveldb/table/format.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_ -#define STORAGE_LEVELDB_TABLE_FORMAT_H_ - -#include -#include -#include "leveldb/slice.h" -#include "leveldb/status.h" -#include "leveldb/table_builder.h" - -namespace leveldb { - -class Block; -class RandomAccessFile; -struct ReadOptions; - -// BlockHandle is a pointer to the extent of a file that stores a data -// block or a meta block. -class BlockHandle { - public: - BlockHandle(); - - // The offset of the block in the file. - uint64_t offset() const { return offset_; } - void set_offset(uint64_t offset) { offset_ = offset; } - - // The size of the stored block - uint64_t size() const { return size_; } - void set_size(uint64_t size) { size_ = size; } - - void EncodeTo(std::string* dst) const; - Status DecodeFrom(Slice* input); - - // Maximum encoding length of a BlockHandle - enum { kMaxEncodedLength = 10 + 10 }; - - private: - uint64_t offset_; - uint64_t size_; -}; - -// Footer encapsulates the fixed information stored at the tail -// end of every table file. -class Footer { - public: - Footer() { } - - // The block handle for the metaindex block of the table - const BlockHandle& metaindex_handle() const { return metaindex_handle_; } - void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } - - // The block handle for the index block of the table - const BlockHandle& index_handle() const { - return index_handle_; - } - void set_index_handle(const BlockHandle& h) { - index_handle_ = h; - } - - void EncodeTo(std::string* dst) const; - Status DecodeFrom(Slice* input); - - // Encoded length of a Footer. Note that the serialization of a - // Footer will always occupy exactly this many bytes. It consists - // of two block handles and a magic number. - enum { - kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8 - }; - - private: - BlockHandle metaindex_handle_; - BlockHandle index_handle_; -}; - -// kTableMagicNumber was picked by running -// echo http://code.google.com/p/leveldb/ | sha1sum -// and taking the leading 64 bits. -static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; - -// 1-byte type + 32-bit crc -static const size_t kBlockTrailerSize = 5; - -struct BlockContents { - Slice data; // Actual contents of data - bool cachable; // True iff data can be cached - bool heap_allocated; // True iff caller should delete[] data.data() -}; - -// Read the block identified by "handle" from "file". On failure -// return non-OK. On success fill *result and return OK. -extern Status ReadBlock(RandomAccessFile* file, - const ReadOptions& options, - const BlockHandle& handle, - BlockContents* result); - -// Implementation details follow. Clients should ignore, - -inline BlockHandle::BlockHandle() - : offset_(~static_cast(0)), - size_(~static_cast(0)) { -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/src/leveldb/table/iterator.cc b/src/leveldb/table/iterator.cc deleted file mode 100644 index 3d1c87fde..000000000 --- a/src/leveldb/table/iterator.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/iterator.h" - -namespace leveldb { - -Iterator::Iterator() { - cleanup_.function = NULL; - cleanup_.next = NULL; -} - -Iterator::~Iterator() { - if (cleanup_.function != NULL) { - (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2); - for (Cleanup* c = cleanup_.next; c != NULL; ) { - (*c->function)(c->arg1, c->arg2); - Cleanup* next = c->next; - delete c; - c = next; - } - } -} - -void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { - assert(func != NULL); - Cleanup* c; - if (cleanup_.function == NULL) { - c = &cleanup_; - } else { - c = new Cleanup; - c->next = cleanup_.next; - cleanup_.next = c; - } - c->function = func; - c->arg1 = arg1; - c->arg2 = arg2; -} - -namespace { -class EmptyIterator : public Iterator { - public: - EmptyIterator(const Status& s) : status_(s) { } - virtual bool Valid() const { return false; } - virtual void Seek(const Slice& target) { } - virtual void SeekToFirst() { } - virtual void SeekToLast() { } - virtual void Next() { assert(false); } - virtual void Prev() { assert(false); } - Slice key() const { assert(false); return Slice(); } - Slice value() const { assert(false); return Slice(); } - virtual Status status() const { return status_; } - private: - Status status_; -}; -} // namespace - -Iterator* NewEmptyIterator() { - return new EmptyIterator(Status::OK()); -} - -Iterator* NewErrorIterator(const Status& status) { - return new EmptyIterator(status); -} - -} // namespace leveldb diff --git a/src/leveldb/table/iterator_wrapper.h b/src/leveldb/table/iterator_wrapper.h deleted file mode 100644 index 9e16b3dbe..000000000 --- a/src/leveldb/table/iterator_wrapper.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ -#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ - -namespace leveldb { - -// A internal wrapper class with an interface similar to Iterator that -// caches the valid() and key() results for an underlying iterator. -// This can help avoid virtual function calls and also gives better -// cache locality. -class IteratorWrapper { - public: - IteratorWrapper(): iter_(NULL), valid_(false) { } - explicit IteratorWrapper(Iterator* iter): iter_(NULL) { - Set(iter); - } - ~IteratorWrapper() { delete iter_; } - Iterator* iter() const { return iter_; } - - // Takes ownership of "iter" and will delete it when destroyed, or - // when Set() is invoked again. - void Set(Iterator* iter) { - delete iter_; - iter_ = iter; - if (iter_ == NULL) { - valid_ = false; - } else { - Update(); - } - } - - - // Iterator interface methods - bool Valid() const { return valid_; } - Slice key() const { assert(Valid()); return key_; } - Slice value() const { assert(Valid()); return iter_->value(); } - // Methods below require iter() != NULL - Status status() const { assert(iter_); return iter_->status(); } - void Next() { assert(iter_); iter_->Next(); Update(); } - void Prev() { assert(iter_); iter_->Prev(); Update(); } - void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } - void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } - void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } - - private: - void Update() { - valid_ = iter_->Valid(); - if (valid_) { - key_ = iter_->key(); - } - } - - Iterator* iter_; - bool valid_; - Slice key_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/src/leveldb/table/merger.cc b/src/leveldb/table/merger.cc deleted file mode 100644 index 2dde4dc21..000000000 --- a/src/leveldb/table/merger.cc +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/merger.h" - -#include "leveldb/comparator.h" -#include "leveldb/iterator.h" -#include "table/iterator_wrapper.h" - -namespace leveldb { - -namespace { -class MergingIterator : public Iterator { - public: - MergingIterator(const Comparator* comparator, Iterator** children, int n) - : comparator_(comparator), - children_(new IteratorWrapper[n]), - n_(n), - current_(NULL), - direction_(kForward) { - for (int i = 0; i < n; i++) { - children_[i].Set(children[i]); - } - } - - virtual ~MergingIterator() { - delete[] children_; - } - - virtual bool Valid() const { - return (current_ != NULL); - } - - virtual void SeekToFirst() { - for (int i = 0; i < n_; i++) { - children_[i].SeekToFirst(); - } - FindSmallest(); - direction_ = kForward; - } - - virtual void SeekToLast() { - for (int i = 0; i < n_; i++) { - children_[i].SeekToLast(); - } - FindLargest(); - direction_ = kReverse; - } - - virtual void Seek(const Slice& target) { - for (int i = 0; i < n_; i++) { - children_[i].Seek(target); - } - FindSmallest(); - direction_ = kForward; - } - - virtual void Next() { - assert(Valid()); - - // Ensure that all children are positioned after key(). - // If we are moving in the forward direction, it is already - // true for all of the non-current_ children since current_ is - // the smallest child and key() == current_->key(). Otherwise, - // we explicitly position the non-current_ children. - if (direction_ != kForward) { - for (int i = 0; i < n_; i++) { - IteratorWrapper* child = &children_[i]; - if (child != current_) { - child->Seek(key()); - if (child->Valid() && - comparator_->Compare(key(), child->key()) == 0) { - child->Next(); - } - } - } - direction_ = kForward; - } - - current_->Next(); - FindSmallest(); - } - - virtual void Prev() { - assert(Valid()); - - // Ensure that all children are positioned before key(). - // If we are moving in the reverse direction, it is already - // true for all of the non-current_ children since current_ is - // the largest child and key() == current_->key(). Otherwise, - // we explicitly position the non-current_ children. - if (direction_ != kReverse) { - for (int i = 0; i < n_; i++) { - IteratorWrapper* child = &children_[i]; - if (child != current_) { - child->Seek(key()); - if (child->Valid()) { - // Child is at first entry >= key(). Step back one to be < key() - child->Prev(); - } else { - // Child has no entries >= key(). Position at last entry. - child->SeekToLast(); - } - } - } - direction_ = kReverse; - } - - current_->Prev(); - FindLargest(); - } - - virtual Slice key() const { - assert(Valid()); - return current_->key(); - } - - virtual Slice value() const { - assert(Valid()); - return current_->value(); - } - - virtual Status status() const { - Status status; - for (int i = 0; i < n_; i++) { - status = children_[i].status(); - if (!status.ok()) { - break; - } - } - return status; - } - - private: - void FindSmallest(); - void FindLargest(); - - // We might want to use a heap in case there are lots of children. - // For now we use a simple array since we expect a very small number - // of children in leveldb. - const Comparator* comparator_; - IteratorWrapper* children_; - int n_; - IteratorWrapper* current_; - - // Which direction is the iterator moving? - enum Direction { - kForward, - kReverse - }; - Direction direction_; -}; - -void MergingIterator::FindSmallest() { - IteratorWrapper* smallest = NULL; - for (int i = 0; i < n_; i++) { - IteratorWrapper* child = &children_[i]; - if (child->Valid()) { - if (smallest == NULL) { - smallest = child; - } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { - smallest = child; - } - } - } - current_ = smallest; -} - -void MergingIterator::FindLargest() { - IteratorWrapper* largest = NULL; - for (int i = n_-1; i >= 0; i--) { - IteratorWrapper* child = &children_[i]; - if (child->Valid()) { - if (largest == NULL) { - largest = child; - } else if (comparator_->Compare(child->key(), largest->key()) > 0) { - largest = child; - } - } - } - current_ = largest; -} -} // namespace - -Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) { - assert(n >= 0); - if (n == 0) { - return NewEmptyIterator(); - } else if (n == 1) { - return list[0]; - } else { - return new MergingIterator(cmp, list, n); - } -} - -} // namespace leveldb diff --git a/src/leveldb/table/merger.h b/src/leveldb/table/merger.h deleted file mode 100644 index 91ddd80fa..000000000 --- a/src/leveldb/table/merger.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_ -#define STORAGE_LEVELDB_TABLE_MERGER_H_ - -namespace leveldb { - -class Comparator; -class Iterator; - -// Return an iterator that provided the union of the data in -// children[0,n-1]. Takes ownership of the child iterators and -// will delete them when the result iterator is deleted. -// -// The result does no duplicate suppression. I.e., if a particular -// key is present in K child iterators, it will be yielded K times. -// -// REQUIRES: n >= 0 -extern Iterator* NewMergingIterator( - const Comparator* comparator, Iterator** children, int n); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc deleted file mode 100644 index dbd6d3a1b..000000000 --- a/src/leveldb/table/table.cc +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/table.h" - -#include "leveldb/cache.h" -#include "leveldb/comparator.h" -#include "leveldb/env.h" -#include "leveldb/filter_policy.h" -#include "leveldb/options.h" -#include "table/block.h" -#include "table/filter_block.h" -#include "table/format.h" -#include "table/two_level_iterator.h" -#include "util/coding.h" - -namespace leveldb { - -struct Table::Rep { - ~Rep() { - delete filter; - delete [] filter_data; - delete index_block; - } - - Options options; - Status status; - RandomAccessFile* file; - uint64_t cache_id; - FilterBlockReader* filter; - const char* filter_data; - - BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer - Block* index_block; -}; - -Status Table::Open(const Options& options, - RandomAccessFile* file, - uint64_t size, - Table** table) { - *table = NULL; - if (size < Footer::kEncodedLength) { - return Status::InvalidArgument("file is too short to be an sstable"); - } - - char footer_space[Footer::kEncodedLength]; - Slice footer_input; - Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, - &footer_input, footer_space); - if (!s.ok()) return s; - - Footer footer; - s = footer.DecodeFrom(&footer_input); - if (!s.ok()) return s; - - // Read the index block - BlockContents contents; - Block* index_block = NULL; - if (s.ok()) { - s = ReadBlock(file, ReadOptions(), footer.index_handle(), &contents); - if (s.ok()) { - index_block = new Block(contents); - } - } - - if (s.ok()) { - // We've successfully read the footer and the index block: we're - // ready to serve requests. - Rep* rep = new Table::Rep; - rep->options = options; - rep->file = file; - rep->metaindex_handle = footer.metaindex_handle(); - rep->index_block = index_block; - rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); - rep->filter_data = NULL; - rep->filter = NULL; - *table = new Table(rep); - (*table)->ReadMeta(footer); - } else { - if (index_block) delete index_block; - } - - return s; -} - -void Table::ReadMeta(const Footer& footer) { - if (rep_->options.filter_policy == NULL) { - return; // Do not need any metadata - } - - // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates - // it is an empty block. - ReadOptions opt; - BlockContents contents; - if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { - // Do not propagate errors since meta info is not needed for operation - return; - } - Block* meta = new Block(contents); - - Iterator* iter = meta->NewIterator(BytewiseComparator()); - std::string key = "filter."; - key.append(rep_->options.filter_policy->Name()); - iter->Seek(key); - if (iter->Valid() && iter->key() == Slice(key)) { - ReadFilter(iter->value()); - } - delete iter; - delete meta; -} - -void Table::ReadFilter(const Slice& filter_handle_value) { - Slice v = filter_handle_value; - BlockHandle filter_handle; - if (!filter_handle.DecodeFrom(&v).ok()) { - return; - } - - // We might want to unify with ReadBlock() if we start - // requiring checksum verification in Table::Open. - ReadOptions opt; - BlockContents block; - if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { - return; - } - if (block.heap_allocated) { - rep_->filter_data = block.data.data(); // Will need to delete later - } - rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); -} - -Table::~Table() { - delete rep_; -} - -static void DeleteBlock(void* arg, void* ignored) { - delete reinterpret_cast(arg); -} - -static void DeleteCachedBlock(const Slice& key, void* value) { - Block* block = reinterpret_cast(value); - delete block; -} - -static void ReleaseBlock(void* arg, void* h) { - Cache* cache = reinterpret_cast(arg); - Cache::Handle* handle = reinterpret_cast(h); - cache->Release(handle); -} - -// Convert an index iterator value (i.e., an encoded BlockHandle) -// into an iterator over the contents of the corresponding block. -Iterator* Table::BlockReader(void* arg, - const ReadOptions& options, - const Slice& index_value) { - Table* table = reinterpret_cast(arg); - Cache* block_cache = table->rep_->options.block_cache; - Block* block = NULL; - Cache::Handle* cache_handle = NULL; - - BlockHandle handle; - Slice input = index_value; - Status s = handle.DecodeFrom(&input); - // We intentionally allow extra stuff in index_value so that we - // can add more features in the future. - - if (s.ok()) { - BlockContents contents; - if (block_cache != NULL) { - char cache_key_buffer[16]; - EncodeFixed64(cache_key_buffer, table->rep_->cache_id); - EncodeFixed64(cache_key_buffer+8, handle.offset()); - Slice key(cache_key_buffer, sizeof(cache_key_buffer)); - cache_handle = block_cache->Lookup(key); - if (cache_handle != NULL) { - block = reinterpret_cast(block_cache->Value(cache_handle)); - } else { - s = ReadBlock(table->rep_->file, options, handle, &contents); - if (s.ok()) { - block = new Block(contents); - if (contents.cachable && options.fill_cache) { - cache_handle = block_cache->Insert( - key, block, block->size(), &DeleteCachedBlock); - } - } - } - } else { - s = ReadBlock(table->rep_->file, options, handle, &contents); - if (s.ok()) { - block = new Block(contents); - } - } - } - - Iterator* iter; - if (block != NULL) { - iter = block->NewIterator(table->rep_->options.comparator); - if (cache_handle == NULL) { - iter->RegisterCleanup(&DeleteBlock, block, NULL); - } else { - iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); - } - } else { - iter = NewErrorIterator(s); - } - return iter; -} - -Iterator* Table::NewIterator(const ReadOptions& options) const { - return NewTwoLevelIterator( - rep_->index_block->NewIterator(rep_->options.comparator), - &Table::BlockReader, const_cast(this), options); -} - -Status Table::InternalGet(const ReadOptions& options, const Slice& k, - void* arg, - void (*saver)(void*, const Slice&, const Slice&)) { - Status s; - Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); - iiter->Seek(k); - if (iiter->Valid()) { - Slice handle_value = iiter->value(); - FilterBlockReader* filter = rep_->filter; - BlockHandle handle; - if (filter != NULL && - handle.DecodeFrom(&handle_value).ok() && - !filter->KeyMayMatch(handle.offset(), k)) { - // Not found - } else { - Slice handle = iiter->value(); - Iterator* block_iter = BlockReader(this, options, iiter->value()); - block_iter->Seek(k); - if (block_iter->Valid()) { - (*saver)(arg, block_iter->key(), block_iter->value()); - } - s = block_iter->status(); - delete block_iter; - } - } - if (s.ok()) { - s = iiter->status(); - } - delete iiter; - return s; -} - - -uint64_t Table::ApproximateOffsetOf(const Slice& key) const { - Iterator* index_iter = - rep_->index_block->NewIterator(rep_->options.comparator); - index_iter->Seek(key); - uint64_t result; - if (index_iter->Valid()) { - BlockHandle handle; - Slice input = index_iter->value(); - Status s = handle.DecodeFrom(&input); - if (s.ok()) { - result = handle.offset(); - } else { - // Strange: we can't decode the block handle in the index block. - // We'll just return the offset of the metaindex block, which is - // close to the whole file size for this case. - result = rep_->metaindex_handle.offset(); - } - } else { - // key is past the last key in the file. Approximate the offset - // by returning the offset of the metaindex block (which is - // right near the end of the file). - result = rep_->metaindex_handle.offset(); - } - delete index_iter; - return result; -} - -} // namespace leveldb diff --git a/src/leveldb/table/table_builder.cc b/src/leveldb/table/table_builder.cc deleted file mode 100644 index 62002c84f..000000000 --- a/src/leveldb/table/table_builder.cc +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/table_builder.h" - -#include -#include "leveldb/comparator.h" -#include "leveldb/env.h" -#include "leveldb/filter_policy.h" -#include "leveldb/options.h" -#include "table/block_builder.h" -#include "table/filter_block.h" -#include "table/format.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { - -struct TableBuilder::Rep { - Options options; - Options index_block_options; - WritableFile* file; - uint64_t offset; - Status status; - BlockBuilder data_block; - BlockBuilder index_block; - std::string last_key; - int64_t num_entries; - bool closed; // Either Finish() or Abandon() has been called. - FilterBlockBuilder* filter_block; - - // We do not emit the index entry for a block until we have seen the - // first key for the next data block. This allows us to use shorter - // keys in the index block. For example, consider a block boundary - // between the keys "the quick brown fox" and "the who". We can use - // "the r" as the key for the index block entry since it is >= all - // entries in the first block and < all entries in subsequent - // blocks. - // - // Invariant: r->pending_index_entry is true only if data_block is empty. - bool pending_index_entry; - BlockHandle pending_handle; // Handle to add to index block - - std::string compressed_output; - - Rep(const Options& opt, WritableFile* f) - : options(opt), - index_block_options(opt), - file(f), - offset(0), - data_block(&options), - index_block(&index_block_options), - num_entries(0), - closed(false), - filter_block(opt.filter_policy == NULL ? NULL - : new FilterBlockBuilder(opt.filter_policy)), - pending_index_entry(false) { - index_block_options.block_restart_interval = 1; - } -}; - -TableBuilder::TableBuilder(const Options& options, WritableFile* file) - : rep_(new Rep(options, file)) { - if (rep_->filter_block != NULL) { - rep_->filter_block->StartBlock(0); - } -} - -TableBuilder::~TableBuilder() { - assert(rep_->closed); // Catch errors where caller forgot to call Finish() - delete rep_->filter_block; - delete rep_; -} - -Status TableBuilder::ChangeOptions(const Options& options) { - // Note: if more fields are added to Options, update - // this function to catch changes that should not be allowed to - // change in the middle of building a Table. - if (options.comparator != rep_->options.comparator) { - return Status::InvalidArgument("changing comparator while building table"); - } - - // Note that any live BlockBuilders point to rep_->options and therefore - // will automatically pick up the updated options. - rep_->options = options; - rep_->index_block_options = options; - rep_->index_block_options.block_restart_interval = 1; - return Status::OK(); -} - -void TableBuilder::Add(const Slice& key, const Slice& value) { - Rep* r = rep_; - assert(!r->closed); - if (!ok()) return; - if (r->num_entries > 0) { - assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); - } - - if (r->pending_index_entry) { - assert(r->data_block.empty()); - r->options.comparator->FindShortestSeparator(&r->last_key, key); - std::string handle_encoding; - r->pending_handle.EncodeTo(&handle_encoding); - r->index_block.Add(r->last_key, Slice(handle_encoding)); - r->pending_index_entry = false; - } - - if (r->filter_block != NULL) { - r->filter_block->AddKey(key); - } - - r->last_key.assign(key.data(), key.size()); - r->num_entries++; - r->data_block.Add(key, value); - - const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); - if (estimated_block_size >= r->options.block_size) { - Flush(); - } -} - -void TableBuilder::Flush() { - Rep* r = rep_; - assert(!r->closed); - if (!ok()) return; - if (r->data_block.empty()) return; - assert(!r->pending_index_entry); - WriteBlock(&r->data_block, &r->pending_handle); - if (ok()) { - r->pending_index_entry = true; - r->status = r->file->Flush(); - } - if (r->filter_block != NULL) { - r->filter_block->StartBlock(r->offset); - } -} - -void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { - // File format contains a sequence of blocks where each block has: - // block_data: uint8[n] - // type: uint8 - // crc: uint32 - assert(ok()); - Rep* r = rep_; - Slice raw = block->Finish(); - - Slice block_contents; - CompressionType type = r->options.compression; - // TODO(postrelease): Support more compression options: zlib? - switch (type) { - case kNoCompression: - block_contents = raw; - break; - - case kSnappyCompression: { - std::string* compressed = &r->compressed_output; - if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && - compressed->size() < raw.size() - (raw.size() / 8u)) { - block_contents = *compressed; - } else { - // Snappy not supported, or compressed less than 12.5%, so just - // store uncompressed form - block_contents = raw; - type = kNoCompression; - } - break; - } - } - WriteRawBlock(block_contents, type, handle); - r->compressed_output.clear(); - block->Reset(); -} - -void TableBuilder::WriteRawBlock(const Slice& block_contents, - CompressionType type, - BlockHandle* handle) { - Rep* r = rep_; - handle->set_offset(r->offset); - handle->set_size(block_contents.size()); - r->status = r->file->Append(block_contents); - if (r->status.ok()) { - char trailer[kBlockTrailerSize]; - trailer[0] = type; - uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); - crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type - EncodeFixed32(trailer+1, crc32c::Mask(crc)); - r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); - if (r->status.ok()) { - r->offset += block_contents.size() + kBlockTrailerSize; - } - } -} - -Status TableBuilder::status() const { - return rep_->status; -} - -Status TableBuilder::Finish() { - Rep* r = rep_; - Flush(); - assert(!r->closed); - r->closed = true; - - BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; - - // Write filter block - if (ok() && r->filter_block != NULL) { - WriteRawBlock(r->filter_block->Finish(), kNoCompression, - &filter_block_handle); - } - - // Write metaindex block - if (ok()) { - BlockBuilder meta_index_block(&r->options); - if (r->filter_block != NULL) { - // Add mapping from "filter.Name" to location of filter data - std::string key = "filter."; - key.append(r->options.filter_policy->Name()); - std::string handle_encoding; - filter_block_handle.EncodeTo(&handle_encoding); - meta_index_block.Add(key, handle_encoding); - } - - // TODO(postrelease): Add stats and other meta blocks - WriteBlock(&meta_index_block, &metaindex_block_handle); - } - - // Write index block - if (ok()) { - if (r->pending_index_entry) { - r->options.comparator->FindShortSuccessor(&r->last_key); - std::string handle_encoding; - r->pending_handle.EncodeTo(&handle_encoding); - r->index_block.Add(r->last_key, Slice(handle_encoding)); - r->pending_index_entry = false; - } - WriteBlock(&r->index_block, &index_block_handle); - } - - // Write footer - if (ok()) { - Footer footer; - footer.set_metaindex_handle(metaindex_block_handle); - footer.set_index_handle(index_block_handle); - std::string footer_encoding; - footer.EncodeTo(&footer_encoding); - r->status = r->file->Append(footer_encoding); - if (r->status.ok()) { - r->offset += footer_encoding.size(); - } - } - return r->status; -} - -void TableBuilder::Abandon() { - Rep* r = rep_; - assert(!r->closed); - r->closed = true; -} - -uint64_t TableBuilder::NumEntries() const { - return rep_->num_entries; -} - -uint64_t TableBuilder::FileSize() const { - return rep_->offset; -} - -} // namespace leveldb diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc deleted file mode 100644 index 57cea2533..000000000 --- a/src/leveldb/table/table_test.cc +++ /dev/null @@ -1,838 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/table.h" - -#include -#include -#include "db/dbformat.h" -#include "db/memtable.h" -#include "db/write_batch_internal.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "leveldb/table_builder.h" -#include "table/block.h" -#include "table/block_builder.h" -#include "table/format.h" -#include "util/random.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -// Return reverse of "key". -// Used to test non-lexicographic comparators. -static std::string Reverse(const Slice& key) { - std::string str(key.ToString()); - std::string rev(""); - for (std::string::reverse_iterator rit = str.rbegin(); - rit != str.rend(); ++rit) { - rev.push_back(*rit); - } - return rev; -} - -namespace { -class ReverseKeyComparator : public Comparator { - public: - virtual const char* Name() const { - return "leveldb.ReverseBytewiseComparator"; - } - - virtual int Compare(const Slice& a, const Slice& b) const { - return BytewiseComparator()->Compare(Reverse(a), Reverse(b)); - } - - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const { - std::string s = Reverse(*start); - std::string l = Reverse(limit); - BytewiseComparator()->FindShortestSeparator(&s, l); - *start = Reverse(s); - } - - virtual void FindShortSuccessor(std::string* key) const { - std::string s = Reverse(*key); - BytewiseComparator()->FindShortSuccessor(&s); - *key = Reverse(s); - } -}; -} // namespace -static ReverseKeyComparator reverse_key_comparator; - -static void Increment(const Comparator* cmp, std::string* key) { - if (cmp == BytewiseComparator()) { - key->push_back('\0'); - } else { - assert(cmp == &reverse_key_comparator); - std::string rev = Reverse(*key); - rev.push_back('\0'); - *key = Reverse(rev); - } -} - -// An STL comparator that uses a Comparator -namespace { -struct STLLessThan { - const Comparator* cmp; - - STLLessThan() : cmp(BytewiseComparator()) { } - STLLessThan(const Comparator* c) : cmp(c) { } - bool operator()(const std::string& a, const std::string& b) const { - return cmp->Compare(Slice(a), Slice(b)) < 0; - } -}; -} // namespace - -class StringSink: public WritableFile { - public: - ~StringSink() { } - - const std::string& contents() const { return contents_; } - - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - - virtual Status Append(const Slice& data) { - contents_.append(data.data(), data.size()); - return Status::OK(); - } - - private: - std::string contents_; -}; - - -class StringSource: public RandomAccessFile { - public: - StringSource(const Slice& contents) - : contents_(contents.data(), contents.size()) { - } - - virtual ~StringSource() { } - - uint64_t Size() const { return contents_.size(); } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - if (offset > contents_.size()) { - return Status::InvalidArgument("invalid Read offset"); - } - if (offset + n > contents_.size()) { - n = contents_.size() - offset; - } - memcpy(scratch, &contents_[offset], n); - *result = Slice(scratch, n); - return Status::OK(); - } - - private: - std::string contents_; -}; - -typedef std::map KVMap; - -// Helper class for tests to unify the interface between -// BlockBuilder/TableBuilder and Block/Table. -class Constructor { - public: - explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { } - virtual ~Constructor() { } - - void Add(const std::string& key, const Slice& value) { - data_[key] = value.ToString(); - } - - // Finish constructing the data structure with all the keys that have - // been added so far. Returns the keys in sorted order in "*keys" - // and stores the key/value pairs in "*kvmap" - void Finish(const Options& options, - std::vector* keys, - KVMap* kvmap) { - *kvmap = data_; - keys->clear(); - for (KVMap::const_iterator it = data_.begin(); - it != data_.end(); - ++it) { - keys->push_back(it->first); - } - data_.clear(); - Status s = FinishImpl(options, *kvmap); - ASSERT_TRUE(s.ok()) << s.ToString(); - } - - // Construct the data structure from the data in "data" - virtual Status FinishImpl(const Options& options, const KVMap& data) = 0; - - virtual Iterator* NewIterator() const = 0; - - virtual const KVMap& data() { return data_; } - - virtual DB* db() const { return NULL; } // Overridden in DBConstructor - - private: - KVMap data_; -}; - -class BlockConstructor: public Constructor { - public: - explicit BlockConstructor(const Comparator* cmp) - : Constructor(cmp), - comparator_(cmp), - block_(NULL) { } - ~BlockConstructor() { - delete block_; - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - delete block_; - block_ = NULL; - BlockBuilder builder(&options); - - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - builder.Add(it->first, it->second); - } - // Open the block - data_ = builder.Finish().ToString(); - BlockContents contents; - contents.data = data_; - contents.cachable = false; - contents.heap_allocated = false; - block_ = new Block(contents); - return Status::OK(); - } - virtual Iterator* NewIterator() const { - return block_->NewIterator(comparator_); - } - - private: - const Comparator* comparator_; - std::string data_; - Block* block_; - - BlockConstructor(); -}; - -class TableConstructor: public Constructor { - public: - TableConstructor(const Comparator* cmp) - : Constructor(cmp), - source_(NULL), table_(NULL) { - } - ~TableConstructor() { - Reset(); - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - Reset(); - StringSink sink; - TableBuilder builder(options, &sink); - - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - builder.Add(it->first, it->second); - ASSERT_TRUE(builder.status().ok()); - } - Status s = builder.Finish(); - ASSERT_TRUE(s.ok()) << s.ToString(); - - ASSERT_EQ(sink.contents().size(), builder.FileSize()); - - // Open the table - source_ = new StringSource(sink.contents()); - Options table_options; - table_options.comparator = options.comparator; - return Table::Open(table_options, source_, sink.contents().size(), &table_); - } - - virtual Iterator* NewIterator() const { - return table_->NewIterator(ReadOptions()); - } - - uint64_t ApproximateOffsetOf(const Slice& key) const { - return table_->ApproximateOffsetOf(key); - } - - private: - void Reset() { - delete table_; - delete source_; - table_ = NULL; - source_ = NULL; - } - - StringSource* source_; - Table* table_; - - TableConstructor(); -}; - -// A helper class that converts internal format keys into user keys -class KeyConvertingIterator: public Iterator { - public: - explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { } - virtual ~KeyConvertingIterator() { delete iter_; } - virtual bool Valid() const { return iter_->Valid(); } - virtual void Seek(const Slice& target) { - ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue); - std::string encoded; - AppendInternalKey(&encoded, ikey); - iter_->Seek(encoded); - } - virtual void SeekToFirst() { iter_->SeekToFirst(); } - virtual void SeekToLast() { iter_->SeekToLast(); } - virtual void Next() { iter_->Next(); } - virtual void Prev() { iter_->Prev(); } - - virtual Slice key() const { - assert(Valid()); - ParsedInternalKey key; - if (!ParseInternalKey(iter_->key(), &key)) { - status_ = Status::Corruption("malformed internal key"); - return Slice("corrupted key"); - } - return key.user_key; - } - - virtual Slice value() const { return iter_->value(); } - virtual Status status() const { - return status_.ok() ? iter_->status() : status_; - } - - private: - mutable Status status_; - Iterator* iter_; - - // No copying allowed - KeyConvertingIterator(const KeyConvertingIterator&); - void operator=(const KeyConvertingIterator&); -}; - -class MemTableConstructor: public Constructor { - public: - explicit MemTableConstructor(const Comparator* cmp) - : Constructor(cmp), - internal_comparator_(cmp) { - memtable_ = new MemTable(internal_comparator_); - memtable_->Ref(); - } - ~MemTableConstructor() { - memtable_->Unref(); - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - memtable_->Unref(); - memtable_ = new MemTable(internal_comparator_); - memtable_->Ref(); - int seq = 1; - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - memtable_->Add(seq, kTypeValue, it->first, it->second); - seq++; - } - return Status::OK(); - } - virtual Iterator* NewIterator() const { - return new KeyConvertingIterator(memtable_->NewIterator()); - } - - private: - InternalKeyComparator internal_comparator_; - MemTable* memtable_; -}; - -class DBConstructor: public Constructor { - public: - explicit DBConstructor(const Comparator* cmp) - : Constructor(cmp), - comparator_(cmp) { - db_ = NULL; - NewDB(); - } - ~DBConstructor() { - delete db_; - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - delete db_; - db_ = NULL; - NewDB(); - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - WriteBatch batch; - batch.Put(it->first, it->second); - ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok()); - } - return Status::OK(); - } - virtual Iterator* NewIterator() const { - return db_->NewIterator(ReadOptions()); - } - - virtual DB* db() const { return db_; } - - private: - void NewDB() { - std::string name = test::TmpDir() + "/table_testdb"; - - Options options; - options.comparator = comparator_; - Status status = DestroyDB(name, options); - ASSERT_TRUE(status.ok()) << status.ToString(); - - options.create_if_missing = true; - options.error_if_exists = true; - options.write_buffer_size = 10000; // Something small to force merging - status = DB::Open(options, name, &db_); - ASSERT_TRUE(status.ok()) << status.ToString(); - } - - const Comparator* comparator_; - DB* db_; -}; - -enum TestType { - TABLE_TEST, - BLOCK_TEST, - MEMTABLE_TEST, - DB_TEST -}; - -struct TestArgs { - TestType type; - bool reverse_compare; - int restart_interval; -}; - -static const TestArgs kTestArgList[] = { - { TABLE_TEST, false, 16 }, - { TABLE_TEST, false, 1 }, - { TABLE_TEST, false, 1024 }, - { TABLE_TEST, true, 16 }, - { TABLE_TEST, true, 1 }, - { TABLE_TEST, true, 1024 }, - - { BLOCK_TEST, false, 16 }, - { BLOCK_TEST, false, 1 }, - { BLOCK_TEST, false, 1024 }, - { BLOCK_TEST, true, 16 }, - { BLOCK_TEST, true, 1 }, - { BLOCK_TEST, true, 1024 }, - - // Restart interval does not matter for memtables - { MEMTABLE_TEST, false, 16 }, - { MEMTABLE_TEST, true, 16 }, - - // Do not bother with restart interval variations for DB - { DB_TEST, false, 16 }, - { DB_TEST, true, 16 }, -}; -static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]); - -class Harness { - public: - Harness() : constructor_(NULL) { } - - void Init(const TestArgs& args) { - delete constructor_; - constructor_ = NULL; - options_ = Options(); - - options_.block_restart_interval = args.restart_interval; - // Use shorter block size for tests to exercise block boundary - // conditions more. - options_.block_size = 256; - if (args.reverse_compare) { - options_.comparator = &reverse_key_comparator; - } - switch (args.type) { - case TABLE_TEST: - constructor_ = new TableConstructor(options_.comparator); - break; - case BLOCK_TEST: - constructor_ = new BlockConstructor(options_.comparator); - break; - case MEMTABLE_TEST: - constructor_ = new MemTableConstructor(options_.comparator); - break; - case DB_TEST: - constructor_ = new DBConstructor(options_.comparator); - break; - } - } - - ~Harness() { - delete constructor_; - } - - void Add(const std::string& key, const std::string& value) { - constructor_->Add(key, value); - } - - void Test(Random* rnd) { - std::vector keys; - KVMap data; - constructor_->Finish(options_, &keys, &data); - - TestForwardScan(keys, data); - TestBackwardScan(keys, data); - TestRandomAccess(rnd, keys, data); - } - - void TestForwardScan(const std::vector& keys, - const KVMap& data) { - Iterator* iter = constructor_->NewIterator(); - ASSERT_TRUE(!iter->Valid()); - iter->SeekToFirst(); - for (KVMap::const_iterator model_iter = data.begin(); - model_iter != data.end(); - ++model_iter) { - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - iter->Next(); - } - ASSERT_TRUE(!iter->Valid()); - delete iter; - } - - void TestBackwardScan(const std::vector& keys, - const KVMap& data) { - Iterator* iter = constructor_->NewIterator(); - ASSERT_TRUE(!iter->Valid()); - iter->SeekToLast(); - for (KVMap::const_reverse_iterator model_iter = data.rbegin(); - model_iter != data.rend(); - ++model_iter) { - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - iter->Prev(); - } - ASSERT_TRUE(!iter->Valid()); - delete iter; - } - - void TestRandomAccess(Random* rnd, - const std::vector& keys, - const KVMap& data) { - static const bool kVerbose = false; - Iterator* iter = constructor_->NewIterator(); - ASSERT_TRUE(!iter->Valid()); - KVMap::const_iterator model_iter = data.begin(); - if (kVerbose) fprintf(stderr, "---\n"); - for (int i = 0; i < 200; i++) { - const int toss = rnd->Uniform(5); - switch (toss) { - case 0: { - if (iter->Valid()) { - if (kVerbose) fprintf(stderr, "Next\n"); - iter->Next(); - ++model_iter; - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - } - break; - } - - case 1: { - if (kVerbose) fprintf(stderr, "SeekToFirst\n"); - iter->SeekToFirst(); - model_iter = data.begin(); - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - break; - } - - case 2: { - std::string key = PickRandomKey(rnd, keys); - model_iter = data.lower_bound(key); - if (kVerbose) fprintf(stderr, "Seek '%s'\n", - EscapeString(key).c_str()); - iter->Seek(Slice(key)); - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - break; - } - - case 3: { - if (iter->Valid()) { - if (kVerbose) fprintf(stderr, "Prev\n"); - iter->Prev(); - if (model_iter == data.begin()) { - model_iter = data.end(); // Wrap around to invalid value - } else { - --model_iter; - } - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - } - break; - } - - case 4: { - if (kVerbose) fprintf(stderr, "SeekToLast\n"); - iter->SeekToLast(); - if (keys.empty()) { - model_iter = data.end(); - } else { - std::string last = data.rbegin()->first; - model_iter = data.lower_bound(last); - } - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - break; - } - } - } - delete iter; - } - - std::string ToString(const KVMap& data, const KVMap::const_iterator& it) { - if (it == data.end()) { - return "END"; - } else { - return "'" + it->first + "->" + it->second + "'"; - } - } - - std::string ToString(const KVMap& data, - const KVMap::const_reverse_iterator& it) { - if (it == data.rend()) { - return "END"; - } else { - return "'" + it->first + "->" + it->second + "'"; - } - } - - std::string ToString(const Iterator* it) { - if (!it->Valid()) { - return "END"; - } else { - return "'" + it->key().ToString() + "->" + it->value().ToString() + "'"; - } - } - - std::string PickRandomKey(Random* rnd, const std::vector& keys) { - if (keys.empty()) { - return "foo"; - } else { - const int index = rnd->Uniform(keys.size()); - std::string result = keys[index]; - switch (rnd->Uniform(3)) { - case 0: - // Return an existing key - break; - case 1: { - // Attempt to return something smaller than an existing key - if (result.size() > 0 && result[result.size()-1] > '\0') { - result[result.size()-1]--; - } - break; - } - case 2: { - // Return something larger than an existing key - Increment(options_.comparator, &result); - break; - } - } - return result; - } - } - - // Returns NULL if not running against a DB - DB* db() const { return constructor_->db(); } - - private: - Options options_; - Constructor* constructor_; -}; - -// Test the empty key -TEST(Harness, SimpleEmptyKey) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 1); - Add("", "v"); - Test(&rnd); - } -} - -TEST(Harness, SimpleSingle) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 2); - Add("abc", "v"); - Test(&rnd); - } -} - -TEST(Harness, SimpleMulti) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 3); - Add("abc", "v"); - Add("abcd", "v"); - Add("ac", "v2"); - Test(&rnd); - } -} - -TEST(Harness, SimpleSpecialKey) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 4); - Add("\xff\xff", "v3"); - Test(&rnd); - } -} - -TEST(Harness, Randomized) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 5); - for (int num_entries = 0; num_entries < 2000; - num_entries += (num_entries < 50 ? 1 : 200)) { - if ((num_entries % 10) == 0) { - fprintf(stderr, "case %d of %d: num_entries = %d\n", - (i + 1), int(kNumTestArgs), num_entries); - } - for (int e = 0; e < num_entries; e++) { - std::string v; - Add(test::RandomKey(&rnd, rnd.Skewed(4)), - test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); - } - Test(&rnd); - } - } -} - -TEST(Harness, RandomizedLongDB) { - Random rnd(test::RandomSeed()); - TestArgs args = { DB_TEST, false, 16 }; - Init(args); - int num_entries = 100000; - for (int e = 0; e < num_entries; e++) { - std::string v; - Add(test::RandomKey(&rnd, rnd.Skewed(4)), - test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); - } - Test(&rnd); - - // We must have created enough data to force merging - int files = 0; - for (int level = 0; level < config::kNumLevels; level++) { - std::string value; - char name[100]; - snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level); - ASSERT_TRUE(db()->GetProperty(name, &value)); - files += atoi(value.c_str()); - } - ASSERT_GT(files, 0); -} - -class MemTableTest { }; - -TEST(MemTableTest, Simple) { - InternalKeyComparator cmp(BytewiseComparator()); - MemTable* memtable = new MemTable(cmp); - memtable->Ref(); - WriteBatch batch; - WriteBatchInternal::SetSequence(&batch, 100); - batch.Put(std::string("k1"), std::string("v1")); - batch.Put(std::string("k2"), std::string("v2")); - batch.Put(std::string("k3"), std::string("v3")); - batch.Put(std::string("largekey"), std::string("vlarge")); - ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok()); - - Iterator* iter = memtable->NewIterator(); - iter->SeekToFirst(); - while (iter->Valid()) { - fprintf(stderr, "key: '%s' -> '%s'\n", - iter->key().ToString().c_str(), - iter->value().ToString().c_str()); - iter->Next(); - } - - delete iter; - memtable->Unref(); -} - -static bool Between(uint64_t val, uint64_t low, uint64_t high) { - bool result = (val >= low) && (val <= high); - if (!result) { - fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", - (unsigned long long)(val), - (unsigned long long)(low), - (unsigned long long)(high)); - } - return result; -} - -class TableTest { }; - -TEST(TableTest, ApproximateOffsetOfPlain) { - TableConstructor c(BytewiseComparator()); - c.Add("k01", "hello"); - c.Add("k02", "hello2"); - c.Add("k03", std::string(10000, 'x')); - c.Add("k04", std::string(200000, 'x')); - c.Add("k05", std::string(300000, 'x')); - c.Add("k06", "hello3"); - c.Add("k07", std::string(100000, 'x')); - std::vector keys; - KVMap kvmap; - Options options; - options.block_size = 1024; - options.compression = kNoCompression; - c.Finish(options, &keys, &kvmap); - - ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000)); - -} - -static bool SnappyCompressionSupported() { - std::string out; - Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - return port::Snappy_Compress(in.data(), in.size(), &out); -} - -TEST(TableTest, ApproximateOffsetOfCompressed) { - if (!SnappyCompressionSupported()) { - fprintf(stderr, "skipping compression tests\n"); - return; - } - - Random rnd(301); - TableConstructor c(BytewiseComparator()); - std::string tmp; - c.Add("k01", "hello"); - c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); - c.Add("k03", "hello3"); - c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); - std::vector keys; - KVMap kvmap; - Options options; - options.block_size = 1024; - options.compression = kSnappyCompression; - c.Finish(options, &keys, &kvmap); - - ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000)); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/table/two_level_iterator.cc b/src/leveldb/table/two_level_iterator.cc deleted file mode 100644 index 7822ebab9..000000000 --- a/src/leveldb/table/two_level_iterator.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/two_level_iterator.h" - -#include "leveldb/table.h" -#include "table/block.h" -#include "table/format.h" -#include "table/iterator_wrapper.h" - -namespace leveldb { - -namespace { - -typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); - -class TwoLevelIterator: public Iterator { - public: - TwoLevelIterator( - Iterator* index_iter, - BlockFunction block_function, - void* arg, - const ReadOptions& options); - - virtual ~TwoLevelIterator(); - - virtual void Seek(const Slice& target); - virtual void SeekToFirst(); - virtual void SeekToLast(); - virtual void Next(); - virtual void Prev(); - - virtual bool Valid() const { - return data_iter_.Valid(); - } - virtual Slice key() const { - assert(Valid()); - return data_iter_.key(); - } - virtual Slice value() const { - assert(Valid()); - return data_iter_.value(); - } - virtual Status status() const { - // It'd be nice if status() returned a const Status& instead of a Status - if (!index_iter_.status().ok()) { - return index_iter_.status(); - } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) { - return data_iter_.status(); - } else { - return status_; - } - } - - private: - void SaveError(const Status& s) { - if (status_.ok() && !s.ok()) status_ = s; - } - void SkipEmptyDataBlocksForward(); - void SkipEmptyDataBlocksBackward(); - void SetDataIterator(Iterator* data_iter); - void InitDataBlock(); - - BlockFunction block_function_; - void* arg_; - const ReadOptions options_; - Status status_; - IteratorWrapper index_iter_; - IteratorWrapper data_iter_; // May be NULL - // If data_iter_ is non-NULL, then "data_block_handle_" holds the - // "index_value" passed to block_function_ to create the data_iter_. - std::string data_block_handle_; -}; - -TwoLevelIterator::TwoLevelIterator( - Iterator* index_iter, - BlockFunction block_function, - void* arg, - const ReadOptions& options) - : block_function_(block_function), - arg_(arg), - options_(options), - index_iter_(index_iter), - data_iter_(NULL) { -} - -TwoLevelIterator::~TwoLevelIterator() { -} - -void TwoLevelIterator::Seek(const Slice& target) { - index_iter_.Seek(target); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.Seek(target); - SkipEmptyDataBlocksForward(); -} - -void TwoLevelIterator::SeekToFirst() { - index_iter_.SeekToFirst(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); - SkipEmptyDataBlocksForward(); -} - -void TwoLevelIterator::SeekToLast() { - index_iter_.SeekToLast(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); - SkipEmptyDataBlocksBackward(); -} - -void TwoLevelIterator::Next() { - assert(Valid()); - data_iter_.Next(); - SkipEmptyDataBlocksForward(); -} - -void TwoLevelIterator::Prev() { - assert(Valid()); - data_iter_.Prev(); - SkipEmptyDataBlocksBackward(); -} - - -void TwoLevelIterator::SkipEmptyDataBlocksForward() { - while (data_iter_.iter() == NULL || !data_iter_.Valid()) { - // Move to next block - if (!index_iter_.Valid()) { - SetDataIterator(NULL); - return; - } - index_iter_.Next(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); - } -} - -void TwoLevelIterator::SkipEmptyDataBlocksBackward() { - while (data_iter_.iter() == NULL || !data_iter_.Valid()) { - // Move to next block - if (!index_iter_.Valid()) { - SetDataIterator(NULL); - return; - } - index_iter_.Prev(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); - } -} - -void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { - if (data_iter_.iter() != NULL) SaveError(data_iter_.status()); - data_iter_.Set(data_iter); -} - -void TwoLevelIterator::InitDataBlock() { - if (!index_iter_.Valid()) { - SetDataIterator(NULL); - } else { - Slice handle = index_iter_.value(); - if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) { - // data_iter_ is already constructed with this iterator, so - // no need to change anything - } else { - Iterator* iter = (*block_function_)(arg_, options_, handle); - data_block_handle_.assign(handle.data(), handle.size()); - SetDataIterator(iter); - } - } -} - -} // namespace - -Iterator* NewTwoLevelIterator( - Iterator* index_iter, - BlockFunction block_function, - void* arg, - const ReadOptions& options) { - return new TwoLevelIterator(index_iter, block_function, arg, options); -} - -} // namespace leveldb diff --git a/src/leveldb/table/two_level_iterator.h b/src/leveldb/table/two_level_iterator.h deleted file mode 100644 index 629ca3452..000000000 --- a/src/leveldb/table/two_level_iterator.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ -#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ - -#include "leveldb/iterator.h" - -namespace leveldb { - -struct ReadOptions; - -// Return a new two level iterator. A two-level iterator contains an -// index iterator whose values point to a sequence of blocks where -// each block is itself a sequence of key,value pairs. The returned -// two-level iterator yields the concatenation of all key/value pairs -// in the sequence of blocks. Takes ownership of "index_iter" and -// will delete it when no longer needed. -// -// Uses a supplied function to convert an index_iter value into -// an iterator over the contents of the corresponding block. -extern Iterator* NewTwoLevelIterator( - Iterator* index_iter, - Iterator* (*block_function)( - void* arg, - const ReadOptions& options, - const Slice& index_value), - void* arg, - const ReadOptions& options); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/src/leveldb/util/arena.cc b/src/leveldb/util/arena.cc deleted file mode 100644 index 9551d6a3a..000000000 --- a/src/leveldb/util/arena.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/arena.h" -#include - -namespace leveldb { - -static const int kBlockSize = 4096; - -Arena::Arena() { - blocks_memory_ = 0; - alloc_ptr_ = NULL; // First allocation will allocate a block - alloc_bytes_remaining_ = 0; -} - -Arena::~Arena() { - for (size_t i = 0; i < blocks_.size(); i++) { - delete[] blocks_[i]; - } -} - -char* Arena::AllocateFallback(size_t bytes) { - if (bytes > kBlockSize / 4) { - // Object is more than a quarter of our block size. Allocate it separately - // to avoid wasting too much space in leftover bytes. - char* result = AllocateNewBlock(bytes); - return result; - } - - // We waste the remaining space in the current block. - alloc_ptr_ = AllocateNewBlock(kBlockSize); - alloc_bytes_remaining_ = kBlockSize; - - char* result = alloc_ptr_; - alloc_ptr_ += bytes; - alloc_bytes_remaining_ -= bytes; - return result; -} - -char* Arena::AllocateAligned(size_t bytes) { - const int align = sizeof(void*); // We'll align to pointer size - assert((align & (align-1)) == 0); // Pointer size should be a power of 2 - size_t current_mod = reinterpret_cast(alloc_ptr_) & (align-1); - size_t slop = (current_mod == 0 ? 0 : align - current_mod); - size_t needed = bytes + slop; - char* result; - if (needed <= alloc_bytes_remaining_) { - result = alloc_ptr_ + slop; - alloc_ptr_ += needed; - alloc_bytes_remaining_ -= needed; - } else { - // AllocateFallback always returned aligned memory - result = AllocateFallback(bytes); - } - assert((reinterpret_cast(result) & (align-1)) == 0); - return result; -} - -char* Arena::AllocateNewBlock(size_t block_bytes) { - char* result = new char[block_bytes]; - blocks_memory_ += block_bytes; - blocks_.push_back(result); - return result; -} - -} // namespace leveldb diff --git a/src/leveldb/util/arena.h b/src/leveldb/util/arena.h deleted file mode 100644 index 8f7dde226..000000000 --- a/src/leveldb/util/arena.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_ -#define STORAGE_LEVELDB_UTIL_ARENA_H_ - -#include -#include -#include -#include - -namespace leveldb { - -class Arena { - public: - Arena(); - ~Arena(); - - // Return a pointer to a newly allocated memory block of "bytes" bytes. - char* Allocate(size_t bytes); - - // Allocate memory with the normal alignment guarantees provided by malloc - char* AllocateAligned(size_t bytes); - - // Returns an estimate of the total memory usage of data allocated - // by the arena (including space allocated but not yet used for user - // allocations). - size_t MemoryUsage() const { - return blocks_memory_ + blocks_.capacity() * sizeof(char*); - } - - private: - char* AllocateFallback(size_t bytes); - char* AllocateNewBlock(size_t block_bytes); - - // Allocation state - char* alloc_ptr_; - size_t alloc_bytes_remaining_; - - // Array of new[] allocated memory blocks - std::vector blocks_; - - // Bytes of memory in blocks allocated so far - size_t blocks_memory_; - - // No copying allowed - Arena(const Arena&); - void operator=(const Arena&); -}; - -inline char* Arena::Allocate(size_t bytes) { - // The semantics of what to return are a bit messy if we allow - // 0-byte allocations, so we disallow them here (we don't need - // them for our internal use). - assert(bytes > 0); - if (bytes <= alloc_bytes_remaining_) { - char* result = alloc_ptr_; - alloc_ptr_ += bytes; - alloc_bytes_remaining_ -= bytes; - return result; - } - return AllocateFallback(bytes); -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/src/leveldb/util/arena_test.cc b/src/leveldb/util/arena_test.cc deleted file mode 100644 index 63d177803..000000000 --- a/src/leveldb/util/arena_test.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/arena.h" - -#include "util/random.h" -#include "util/testharness.h" - -namespace leveldb { - -class ArenaTest { }; - -TEST(ArenaTest, Empty) { - Arena arena; -} - -TEST(ArenaTest, Simple) { - std::vector > allocated; - Arena arena; - const int N = 100000; - size_t bytes = 0; - Random rnd(301); - for (int i = 0; i < N; i++) { - size_t s; - if (i % (N / 10) == 0) { - s = i; - } else { - s = rnd.OneIn(4000) ? rnd.Uniform(6000) : - (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20)); - } - if (s == 0) { - // Our arena disallows size 0 allocations. - s = 1; - } - char* r; - if (rnd.OneIn(10)) { - r = arena.AllocateAligned(s); - } else { - r = arena.Allocate(s); - } - - for (int b = 0; b < s; b++) { - // Fill the "i"th allocation with a known bit pattern - r[b] = i % 256; - } - bytes += s; - allocated.push_back(std::make_pair(s, r)); - ASSERT_GE(arena.MemoryUsage(), bytes); - if (i > N/10) { - ASSERT_LE(arena.MemoryUsage(), bytes * 1.10); - } - } - for (int i = 0; i < allocated.size(); i++) { - size_t num_bytes = allocated[i].first; - const char* p = allocated[i].second; - for (int b = 0; b < num_bytes; b++) { - // Check the "i"th allocation for the known bit pattern - ASSERT_EQ(int(p[b]) & 0xff, i % 256); - } - } -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc deleted file mode 100644 index d7941cd21..000000000 --- a/src/leveldb/util/bloom.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/filter_policy.h" - -#include "leveldb/slice.h" -#include "util/hash.h" - -namespace leveldb { - -namespace { -static uint32_t BloomHash(const Slice& key) { - return Hash(key.data(), key.size(), 0xbc9f1d34); -} - -class BloomFilterPolicy : public FilterPolicy { - private: - size_t bits_per_key_; - size_t k_; - - public: - explicit BloomFilterPolicy(int bits_per_key) - : bits_per_key_(bits_per_key) { - // We intentionally round down to reduce probing cost a little bit - k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) - if (k_ < 1) k_ = 1; - if (k_ > 30) k_ = 30; - } - - virtual const char* Name() const { - return "leveldb.BuiltinBloomFilter"; - } - - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { - // Compute bloom filter size (in both bits and bytes) - size_t bits = n * bits_per_key_; - - // For small n, we can see a very high false positive rate. Fix it - // by enforcing a minimum bloom filter length. - if (bits < 64) bits = 64; - - size_t bytes = (bits + 7) / 8; - bits = bytes * 8; - - const size_t init_size = dst->size(); - dst->resize(init_size + bytes, 0); - dst->push_back(static_cast(k_)); // Remember # of probes in filter - char* array = &(*dst)[init_size]; - for (size_t i = 0; i < n; i++) { - // Use double-hashing to generate a sequence of hash values. - // See analysis in [Kirsch,Mitzenmacher 2006]. - uint32_t h = BloomHash(keys[i]); - const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits - for (size_t j = 0; j < k_; j++) { - const uint32_t bitpos = h % bits; - array[bitpos/8] |= (1 << (bitpos % 8)); - h += delta; - } - } - } - - virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { - const size_t len = bloom_filter.size(); - if (len < 2) return false; - - const char* array = bloom_filter.data(); - const size_t bits = (len - 1) * 8; - - // Use the encoded k so that we can read filters generated by - // bloom filters created using different parameters. - const size_t k = array[len-1]; - if (k > 30) { - // Reserved for potentially new encodings for short bloom filters. - // Consider it a match. - return true; - } - - uint32_t h = BloomHash(key); - const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits - for (size_t j = 0; j < k; j++) { - const uint32_t bitpos = h % bits; - if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false; - h += delta; - } - return true; - } -}; -} - -const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { - return new BloomFilterPolicy(bits_per_key); -} - -} // namespace leveldb diff --git a/src/leveldb/util/bloom_test.cc b/src/leveldb/util/bloom_test.cc deleted file mode 100644 index 0bf8e8d6e..000000000 --- a/src/leveldb/util/bloom_test.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/filter_policy.h" - -#include "util/coding.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static const int kVerbose = 1; - -static Slice Key(int i, char* buffer) { - EncodeFixed32(buffer, i); - return Slice(buffer, sizeof(uint32_t)); -} - -class BloomTest { - private: - const FilterPolicy* policy_; - std::string filter_; - std::vector keys_; - - public: - BloomTest() : policy_(NewBloomFilterPolicy(10)) { } - - ~BloomTest() { - delete policy_; - } - - void Reset() { - keys_.clear(); - filter_.clear(); - } - - void Add(const Slice& s) { - keys_.push_back(s.ToString()); - } - - void Build() { - std::vector key_slices; - for (size_t i = 0; i < keys_.size(); i++) { - key_slices.push_back(Slice(keys_[i])); - } - filter_.clear(); - policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_); - keys_.clear(); - if (kVerbose >= 2) DumpFilter(); - } - - size_t FilterSize() const { - return filter_.size(); - } - - void DumpFilter() { - fprintf(stderr, "F("); - for (size_t i = 0; i+1 < filter_.size(); i++) { - const unsigned int c = static_cast(filter_[i]); - for (int j = 0; j < 8; j++) { - fprintf(stderr, "%c", (c & (1 <KeyMayMatch(s, filter_); - } - - double FalsePositiveRate() { - char buffer[sizeof(int)]; - int result = 0; - for (int i = 0; i < 10000; i++) { - if (Matches(Key(i + 1000000000, buffer))) { - result++; - } - } - return result / 10000.0; - } -}; - -TEST(BloomTest, EmptyFilter) { - ASSERT_TRUE(! Matches("hello")); - ASSERT_TRUE(! Matches("world")); -} - -TEST(BloomTest, Small) { - Add("hello"); - Add("world"); - ASSERT_TRUE(Matches("hello")); - ASSERT_TRUE(Matches("world")); - ASSERT_TRUE(! Matches("x")); - ASSERT_TRUE(! Matches("foo")); -} - -static int NextLength(int length) { - if (length < 10) { - length += 1; - } else if (length < 100) { - length += 10; - } else if (length < 1000) { - length += 100; - } else { - length += 1000; - } - return length; -} - -TEST(BloomTest, VaryingLengths) { - char buffer[sizeof(int)]; - - // Count number of filters that significantly exceed the false positive rate - int mediocre_filters = 0; - int good_filters = 0; - - for (int length = 1; length <= 10000; length = NextLength(length)) { - Reset(); - for (int i = 0; i < length; i++) { - Add(Key(i, buffer)); - } - Build(); - - ASSERT_LE(FilterSize(), (length * 10 / 8) + 40) << length; - - // All added keys must match - for (int i = 0; i < length; i++) { - ASSERT_TRUE(Matches(Key(i, buffer))) - << "Length " << length << "; key " << i; - } - - // Check false positive rate - double rate = FalsePositiveRate(); - if (kVerbose >= 1) { - fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", - rate*100.0, length, static_cast(FilterSize())); - } - ASSERT_LE(rate, 0.02); // Must not be over 2% - if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often - else good_filters++; - } - if (kVerbose >= 1) { - fprintf(stderr, "Filters: %d good, %d mediocre\n", - good_filters, mediocre_filters); - } - ASSERT_LE(mediocre_filters, good_filters/5); -} - -// Different bits-per-byte - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc deleted file mode 100644 index 24f1f63f4..000000000 --- a/src/leveldb/util/cache.cc +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include - -#include "leveldb/cache.h" -#include "port/port.h" -#include "util/hash.h" -#include "util/mutexlock.h" - -namespace leveldb { - -Cache::~Cache() { -} - -namespace { - -// LRU cache implementation - -// An entry is a variable length heap-allocated structure. Entries -// are kept in a circular doubly linked list ordered by access time. -struct LRUHandle { - void* value; - void (*deleter)(const Slice&, void* value); - LRUHandle* next_hash; - LRUHandle* next; - LRUHandle* prev; - size_t charge; // TODO(opt): Only allow uint32_t? - size_t key_length; - uint32_t refs; - uint32_t hash; // Hash of key(); used for fast sharding and comparisons - char key_data[1]; // Beginning of key - - Slice key() const { - // For cheaper lookups, we allow a temporary Handle object - // to store a pointer to a key in "value". - if (next == this) { - return *(reinterpret_cast(value)); - } else { - return Slice(key_data, key_length); - } - } -}; - -// We provide our own simple hash table since it removes a whole bunch -// of porting hacks and is also faster than some of the built-in hash -// table implementations in some of the compiler/runtime combinations -// we have tested. E.g., readrandom speeds up by ~5% over the g++ -// 4.4.3's builtin hashtable. -class HandleTable { - public: - HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); } - ~HandleTable() { delete[] list_; } - - LRUHandle* Lookup(const Slice& key, uint32_t hash) { - return *FindPointer(key, hash); - } - - LRUHandle* Insert(LRUHandle* h) { - LRUHandle** ptr = FindPointer(h->key(), h->hash); - LRUHandle* old = *ptr; - h->next_hash = (old == NULL ? NULL : old->next_hash); - *ptr = h; - if (old == NULL) { - ++elems_; - if (elems_ > length_) { - // Since each cache entry is fairly large, we aim for a small - // average linked list length (<= 1). - Resize(); - } - } - return old; - } - - LRUHandle* Remove(const Slice& key, uint32_t hash) { - LRUHandle** ptr = FindPointer(key, hash); - LRUHandle* result = *ptr; - if (result != NULL) { - *ptr = result->next_hash; - --elems_; - } - return result; - } - - private: - // The table consists of an array of buckets where each bucket is - // a linked list of cache entries that hash into the bucket. - uint32_t length_; - uint32_t elems_; - LRUHandle** list_; - - // Return a pointer to slot that points to a cache entry that - // matches key/hash. If there is no such cache entry, return a - // pointer to the trailing slot in the corresponding linked list. - LRUHandle** FindPointer(const Slice& key, uint32_t hash) { - LRUHandle** ptr = &list_[hash & (length_ - 1)]; - while (*ptr != NULL && - ((*ptr)->hash != hash || key != (*ptr)->key())) { - ptr = &(*ptr)->next_hash; - } - return ptr; - } - - void Resize() { - uint32_t new_length = 4; - while (new_length < elems_) { - new_length *= 2; - } - LRUHandle** new_list = new LRUHandle*[new_length]; - memset(new_list, 0, sizeof(new_list[0]) * new_length); - uint32_t count = 0; - for (uint32_t i = 0; i < length_; i++) { - LRUHandle* h = list_[i]; - while (h != NULL) { - LRUHandle* next = h->next_hash; - Slice key = h->key(); - uint32_t hash = h->hash; - LRUHandle** ptr = &new_list[hash & (new_length - 1)]; - h->next_hash = *ptr; - *ptr = h; - h = next; - count++; - } - } - assert(elems_ == count); - delete[] list_; - list_ = new_list; - length_ = new_length; - } -}; - -// A single shard of sharded cache. -class LRUCache { - public: - LRUCache(); - ~LRUCache(); - - // Separate from constructor so caller can easily make an array of LRUCache - void SetCapacity(size_t capacity) { capacity_ = capacity; } - - // Like Cache methods, but with an extra "hash" parameter. - Cache::Handle* Insert(const Slice& key, uint32_t hash, - void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)); - Cache::Handle* Lookup(const Slice& key, uint32_t hash); - void Release(Cache::Handle* handle); - void Erase(const Slice& key, uint32_t hash); - - private: - void LRU_Remove(LRUHandle* e); - void LRU_Append(LRUHandle* e); - void Unref(LRUHandle* e); - - // Initialized before use. - size_t capacity_; - - // mutex_ protects the following state. - port::Mutex mutex_; - size_t usage_; - uint64_t last_id_; - - // Dummy head of LRU list. - // lru.prev is newest entry, lru.next is oldest entry. - LRUHandle lru_; - - HandleTable table_; -}; - -LRUCache::LRUCache() - : usage_(0), - last_id_(0) { - // Make empty circular linked list - lru_.next = &lru_; - lru_.prev = &lru_; -} - -LRUCache::~LRUCache() { - for (LRUHandle* e = lru_.next; e != &lru_; ) { - LRUHandle* next = e->next; - assert(e->refs == 1); // Error if caller has an unreleased handle - Unref(e); - e = next; - } -} - -void LRUCache::Unref(LRUHandle* e) { - assert(e->refs > 0); - e->refs--; - if (e->refs <= 0) { - usage_ -= e->charge; - (*e->deleter)(e->key(), e->value); - free(e); - } -} - -void LRUCache::LRU_Remove(LRUHandle* e) { - e->next->prev = e->prev; - e->prev->next = e->next; -} - -void LRUCache::LRU_Append(LRUHandle* e) { - // Make "e" newest entry by inserting just before lru_ - e->next = &lru_; - e->prev = lru_.prev; - e->prev->next = e; - e->next->prev = e; -} - -Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { - MutexLock l(&mutex_); - LRUHandle* e = table_.Lookup(key, hash); - if (e != NULL) { - e->refs++; - LRU_Remove(e); - LRU_Append(e); - } - return reinterpret_cast(e); -} - -void LRUCache::Release(Cache::Handle* handle) { - MutexLock l(&mutex_); - Unref(reinterpret_cast(handle)); -} - -Cache::Handle* LRUCache::Insert( - const Slice& key, uint32_t hash, void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)) { - MutexLock l(&mutex_); - - LRUHandle* e = reinterpret_cast( - malloc(sizeof(LRUHandle)-1 + key.size())); - e->value = value; - e->deleter = deleter; - e->charge = charge; - e->key_length = key.size(); - e->hash = hash; - e->refs = 2; // One from LRUCache, one for the returned handle - memcpy(e->key_data, key.data(), key.size()); - LRU_Append(e); - usage_ += charge; - - LRUHandle* old = table_.Insert(e); - if (old != NULL) { - LRU_Remove(old); - Unref(old); - } - - while (usage_ > capacity_ && lru_.next != &lru_) { - LRUHandle* old = lru_.next; - LRU_Remove(old); - table_.Remove(old->key(), old->hash); - Unref(old); - } - - return reinterpret_cast(e); -} - -void LRUCache::Erase(const Slice& key, uint32_t hash) { - MutexLock l(&mutex_); - LRUHandle* e = table_.Remove(key, hash); - if (e != NULL) { - LRU_Remove(e); - Unref(e); - } -} - -static const int kNumShardBits = 4; -static const int kNumShards = 1 << kNumShardBits; - -class ShardedLRUCache : public Cache { - private: - LRUCache shard_[kNumShards]; - port::Mutex id_mutex_; - uint64_t last_id_; - - static inline uint32_t HashSlice(const Slice& s) { - return Hash(s.data(), s.size(), 0); - } - - static uint32_t Shard(uint32_t hash) { - return hash >> (32 - kNumShardBits); - } - - public: - explicit ShardedLRUCache(size_t capacity) - : last_id_(0) { - const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; - for (int s = 0; s < kNumShards; s++) { - shard_[s].SetCapacity(per_shard); - } - } - virtual ~ShardedLRUCache() { } - virtual Handle* Insert(const Slice& key, void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)) { - const uint32_t hash = HashSlice(key); - return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); - } - virtual Handle* Lookup(const Slice& key) { - const uint32_t hash = HashSlice(key); - return shard_[Shard(hash)].Lookup(key, hash); - } - virtual void Release(Handle* handle) { - LRUHandle* h = reinterpret_cast(handle); - shard_[Shard(h->hash)].Release(handle); - } - virtual void Erase(const Slice& key) { - const uint32_t hash = HashSlice(key); - shard_[Shard(hash)].Erase(key, hash); - } - virtual void* Value(Handle* handle) { - return reinterpret_cast(handle)->value; - } - virtual uint64_t NewId() { - MutexLock l(&id_mutex_); - return ++(last_id_); - } -}; - -} // end anonymous namespace - -Cache* NewLRUCache(size_t capacity) { - return new ShardedLRUCache(capacity); -} - -} // namespace leveldb diff --git a/src/leveldb/util/cache_test.cc b/src/leveldb/util/cache_test.cc deleted file mode 100644 index 43716715a..000000000 --- a/src/leveldb/util/cache_test.cc +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/cache.h" - -#include -#include "util/coding.h" -#include "util/testharness.h" - -namespace leveldb { - -// Conversions between numeric keys/values and the types expected by Cache. -static std::string EncodeKey(int k) { - std::string result; - PutFixed32(&result, k); - return result; -} -static int DecodeKey(const Slice& k) { - assert(k.size() == 4); - return DecodeFixed32(k.data()); -} -static void* EncodeValue(uintptr_t v) { return reinterpret_cast(v); } -static int DecodeValue(void* v) { return reinterpret_cast(v); } - -class CacheTest { - public: - static CacheTest* current_; - - static void Deleter(const Slice& key, void* v) { - current_->deleted_keys_.push_back(DecodeKey(key)); - current_->deleted_values_.push_back(DecodeValue(v)); - } - - static const int kCacheSize = 1000; - std::vector deleted_keys_; - std::vector deleted_values_; - Cache* cache_; - - CacheTest() : cache_(NewLRUCache(kCacheSize)) { - current_ = this; - } - - ~CacheTest() { - delete cache_; - } - - int Lookup(int key) { - Cache::Handle* handle = cache_->Lookup(EncodeKey(key)); - const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle)); - if (handle != NULL) { - cache_->Release(handle); - } - return r; - } - - void Insert(int key, int value, int charge = 1) { - cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge, - &CacheTest::Deleter)); - } - - void Erase(int key) { - cache_->Erase(EncodeKey(key)); - } -}; -CacheTest* CacheTest::current_; - -TEST(CacheTest, HitAndMiss) { - ASSERT_EQ(-1, Lookup(100)); - - Insert(100, 101); - ASSERT_EQ(101, Lookup(100)); - ASSERT_EQ(-1, Lookup(200)); - ASSERT_EQ(-1, Lookup(300)); - - Insert(200, 201); - ASSERT_EQ(101, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(-1, Lookup(300)); - - Insert(100, 102); - ASSERT_EQ(102, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(-1, Lookup(300)); - - ASSERT_EQ(1, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[0]); - ASSERT_EQ(101, deleted_values_[0]); -} - -TEST(CacheTest, Erase) { - Erase(200); - ASSERT_EQ(0, deleted_keys_.size()); - - Insert(100, 101); - Insert(200, 201); - Erase(100); - ASSERT_EQ(-1, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(1, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[0]); - ASSERT_EQ(101, deleted_values_[0]); - - Erase(100); - ASSERT_EQ(-1, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(1, deleted_keys_.size()); -} - -TEST(CacheTest, EntriesArePinned) { - Insert(100, 101); - Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); - ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); - - Insert(100, 102); - Cache::Handle* h2 = cache_->Lookup(EncodeKey(100)); - ASSERT_EQ(102, DecodeValue(cache_->Value(h2))); - ASSERT_EQ(0, deleted_keys_.size()); - - cache_->Release(h1); - ASSERT_EQ(1, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[0]); - ASSERT_EQ(101, deleted_values_[0]); - - Erase(100); - ASSERT_EQ(-1, Lookup(100)); - ASSERT_EQ(1, deleted_keys_.size()); - - cache_->Release(h2); - ASSERT_EQ(2, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[1]); - ASSERT_EQ(102, deleted_values_[1]); -} - -TEST(CacheTest, EvictionPolicy) { - Insert(100, 101); - Insert(200, 201); - - // Frequently used entry must be kept around - for (int i = 0; i < kCacheSize + 100; i++) { - Insert(1000+i, 2000+i); - ASSERT_EQ(2000+i, Lookup(1000+i)); - ASSERT_EQ(101, Lookup(100)); - } - ASSERT_EQ(101, Lookup(100)); - ASSERT_EQ(-1, Lookup(200)); -} - -TEST(CacheTest, HeavyEntries) { - // Add a bunch of light and heavy entries and then count the combined - // size of items still in the cache, which must be approximately the - // same as the total capacity. - const int kLight = 1; - const int kHeavy = 10; - int added = 0; - int index = 0; - while (added < 2*kCacheSize) { - const int weight = (index & 1) ? kLight : kHeavy; - Insert(index, 1000+index, weight); - added += weight; - index++; - } - - int cached_weight = 0; - for (int i = 0; i < index; i++) { - const int weight = (i & 1 ? kLight : kHeavy); - int r = Lookup(i); - if (r >= 0) { - cached_weight += weight; - ASSERT_EQ(1000+i, r); - } - } - ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10); -} - -TEST(CacheTest, NewId) { - uint64_t a = cache_->NewId(); - uint64_t b = cache_->NewId(); - ASSERT_NE(a, b); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/coding.cc b/src/leveldb/util/coding.cc deleted file mode 100644 index 21e3186d5..000000000 --- a/src/leveldb/util/coding.cc +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/coding.h" - -namespace leveldb { - -void EncodeFixed32(char* buf, uint32_t value) { - if (port::kLittleEndian) { - memcpy(buf, &value, sizeof(value)); - } else { - buf[0] = value & 0xff; - buf[1] = (value >> 8) & 0xff; - buf[2] = (value >> 16) & 0xff; - buf[3] = (value >> 24) & 0xff; - } -} - -void EncodeFixed64(char* buf, uint64_t value) { - if (port::kLittleEndian) { - memcpy(buf, &value, sizeof(value)); - } else { - buf[0] = value & 0xff; - buf[1] = (value >> 8) & 0xff; - buf[2] = (value >> 16) & 0xff; - buf[3] = (value >> 24) & 0xff; - buf[4] = (value >> 32) & 0xff; - buf[5] = (value >> 40) & 0xff; - buf[6] = (value >> 48) & 0xff; - buf[7] = (value >> 56) & 0xff; - } -} - -void PutFixed32(std::string* dst, uint32_t value) { - char buf[sizeof(value)]; - EncodeFixed32(buf, value); - dst->append(buf, sizeof(buf)); -} - -void PutFixed64(std::string* dst, uint64_t value) { - char buf[sizeof(value)]; - EncodeFixed64(buf, value); - dst->append(buf, sizeof(buf)); -} - -char* EncodeVarint32(char* dst, uint32_t v) { - // Operate on characters as unsigneds - unsigned char* ptr = reinterpret_cast(dst); - static const int B = 128; - if (v < (1<<7)) { - *(ptr++) = v; - } else if (v < (1<<14)) { - *(ptr++) = v | B; - *(ptr++) = v>>7; - } else if (v < (1<<21)) { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = v>>14; - } else if (v < (1<<28)) { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = (v>>14) | B; - *(ptr++) = v>>21; - } else { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = (v>>14) | B; - *(ptr++) = (v>>21) | B; - *(ptr++) = v>>28; - } - return reinterpret_cast(ptr); -} - -void PutVarint32(std::string* dst, uint32_t v) { - char buf[5]; - char* ptr = EncodeVarint32(buf, v); - dst->append(buf, ptr - buf); -} - -char* EncodeVarint64(char* dst, uint64_t v) { - static const int B = 128; - unsigned char* ptr = reinterpret_cast(dst); - while (v >= B) { - *(ptr++) = (v & (B-1)) | B; - v >>= 7; - } - *(ptr++) = static_cast(v); - return reinterpret_cast(ptr); -} - -void PutVarint64(std::string* dst, uint64_t v) { - char buf[10]; - char* ptr = EncodeVarint64(buf, v); - dst->append(buf, ptr - buf); -} - -void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { - PutVarint32(dst, value.size()); - dst->append(value.data(), value.size()); -} - -int VarintLength(uint64_t v) { - int len = 1; - while (v >= 128) { - v >>= 7; - len++; - } - return len; -} - -const char* GetVarint32PtrFallback(const char* p, - const char* limit, - uint32_t* value) { - uint32_t result = 0; - for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { - uint32_t byte = *(reinterpret_cast(p)); - p++; - if (byte & 128) { - // More bytes are present - result |= ((byte & 127) << shift); - } else { - result |= (byte << shift); - *value = result; - return reinterpret_cast(p); - } - } - return NULL; -} - -bool GetVarint32(Slice* input, uint32_t* value) { - const char* p = input->data(); - const char* limit = p + input->size(); - const char* q = GetVarint32Ptr(p, limit, value); - if (q == NULL) { - return false; - } else { - *input = Slice(q, limit - q); - return true; - } -} - -const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { - uint64_t result = 0; - for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { - uint64_t byte = *(reinterpret_cast(p)); - p++; - if (byte & 128) { - // More bytes are present - result |= ((byte & 127) << shift); - } else { - result |= (byte << shift); - *value = result; - return reinterpret_cast(p); - } - } - return NULL; -} - -bool GetVarint64(Slice* input, uint64_t* value) { - const char* p = input->data(); - const char* limit = p + input->size(); - const char* q = GetVarint64Ptr(p, limit, value); - if (q == NULL) { - return false; - } else { - *input = Slice(q, limit - q); - return true; - } -} - -const char* GetLengthPrefixedSlice(const char* p, const char* limit, - Slice* result) { - uint32_t len; - p = GetVarint32Ptr(p, limit, &len); - if (p == NULL) return NULL; - if (p + len > limit) return NULL; - *result = Slice(p, len); - return p + len; -} - -bool GetLengthPrefixedSlice(Slice* input, Slice* result) { - uint32_t len; - if (GetVarint32(input, &len) && - input->size() >= len) { - *result = Slice(input->data(), len); - input->remove_prefix(len); - return true; - } else { - return false; - } -} - -} // namespace leveldb diff --git a/src/leveldb/util/coding.h b/src/leveldb/util/coding.h deleted file mode 100644 index 3993c4a75..000000000 --- a/src/leveldb/util/coding.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Endian-neutral encoding: -// * Fixed-length numbers are encoded with least-significant byte first -// * In addition we support variable length "varint" encoding -// * Strings are encoded prefixed by their length in varint format - -#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ -#define STORAGE_LEVELDB_UTIL_CODING_H_ - -#include -#include -#include -#include "leveldb/slice.h" -#include "port/port.h" - -namespace leveldb { - -// Standard Put... routines append to a string -extern void PutFixed32(std::string* dst, uint32_t value); -extern void PutFixed64(std::string* dst, uint64_t value); -extern void PutVarint32(std::string* dst, uint32_t value); -extern void PutVarint64(std::string* dst, uint64_t value); -extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value); - -// Standard Get... routines parse a value from the beginning of a Slice -// and advance the slice past the parsed value. -extern bool GetVarint32(Slice* input, uint32_t* value); -extern bool GetVarint64(Slice* input, uint64_t* value); -extern bool GetLengthPrefixedSlice(Slice* input, Slice* result); - -// Pointer-based variants of GetVarint... These either store a value -// in *v and return a pointer just past the parsed value, or return -// NULL on error. These routines only look at bytes in the range -// [p..limit-1] -extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v); -extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v); - -// Returns the length of the varint32 or varint64 encoding of "v" -extern int VarintLength(uint64_t v); - -// Lower-level versions of Put... that write directly into a character buffer -// REQUIRES: dst has enough space for the value being written -extern void EncodeFixed32(char* dst, uint32_t value); -extern void EncodeFixed64(char* dst, uint64_t value); - -// Lower-level versions of Put... that write directly into a character buffer -// and return a pointer just past the last byte written. -// REQUIRES: dst has enough space for the value being written -extern char* EncodeVarint32(char* dst, uint32_t value); -extern char* EncodeVarint64(char* dst, uint64_t value); - -// Lower-level versions of Get... that read directly from a character buffer -// without any bounds checking. - -inline uint32_t DecodeFixed32(const char* ptr) { - if (port::kLittleEndian) { - // Load the raw bytes - uint32_t result; - memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load - return result; - } else { - return ((static_cast(static_cast(ptr[0]))) - | (static_cast(static_cast(ptr[1])) << 8) - | (static_cast(static_cast(ptr[2])) << 16) - | (static_cast(static_cast(ptr[3])) << 24)); - } -} - -inline uint64_t DecodeFixed64(const char* ptr) { - if (port::kLittleEndian) { - // Load the raw bytes - uint64_t result; - memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load - return result; - } else { - uint64_t lo = DecodeFixed32(ptr); - uint64_t hi = DecodeFixed32(ptr + 4); - return (hi << 32) | lo; - } -} - -// Internal routine for use by fallback path of GetVarint32Ptr -extern const char* GetVarint32PtrFallback(const char* p, - const char* limit, - uint32_t* value); -inline const char* GetVarint32Ptr(const char* p, - const char* limit, - uint32_t* value) { - if (p < limit) { - uint32_t result = *(reinterpret_cast(p)); - if ((result & 128) == 0) { - *value = result; - return p + 1; - } - } - return GetVarint32PtrFallback(p, limit, value); -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/src/leveldb/util/coding_test.cc b/src/leveldb/util/coding_test.cc deleted file mode 100644 index 2c52b17b6..000000000 --- a/src/leveldb/util/coding_test.cc +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/coding.h" - -#include "util/testharness.h" - -namespace leveldb { - -class Coding { }; - -TEST(Coding, Fixed32) { - std::string s; - for (uint32_t v = 0; v < 100000; v++) { - PutFixed32(&s, v); - } - - const char* p = s.data(); - for (uint32_t v = 0; v < 100000; v++) { - uint32_t actual = DecodeFixed32(p); - ASSERT_EQ(v, actual); - p += sizeof(uint32_t); - } -} - -TEST(Coding, Fixed64) { - std::string s; - for (int power = 0; power <= 63; power++) { - uint64_t v = static_cast(1) << power; - PutFixed64(&s, v - 1); - PutFixed64(&s, v + 0); - PutFixed64(&s, v + 1); - } - - const char* p = s.data(); - for (int power = 0; power <= 63; power++) { - uint64_t v = static_cast(1) << power; - uint64_t actual; - actual = DecodeFixed64(p); - ASSERT_EQ(v-1, actual); - p += sizeof(uint64_t); - - actual = DecodeFixed64(p); - ASSERT_EQ(v+0, actual); - p += sizeof(uint64_t); - - actual = DecodeFixed64(p); - ASSERT_EQ(v+1, actual); - p += sizeof(uint64_t); - } -} - -// Test that encoding routines generate little-endian encodings -TEST(Coding, EncodingOutput) { - std::string dst; - PutFixed32(&dst, 0x04030201); - ASSERT_EQ(4, dst.size()); - ASSERT_EQ(0x01, static_cast(dst[0])); - ASSERT_EQ(0x02, static_cast(dst[1])); - ASSERT_EQ(0x03, static_cast(dst[2])); - ASSERT_EQ(0x04, static_cast(dst[3])); - - dst.clear(); - PutFixed64(&dst, 0x0807060504030201ull); - ASSERT_EQ(8, dst.size()); - ASSERT_EQ(0x01, static_cast(dst[0])); - ASSERT_EQ(0x02, static_cast(dst[1])); - ASSERT_EQ(0x03, static_cast(dst[2])); - ASSERT_EQ(0x04, static_cast(dst[3])); - ASSERT_EQ(0x05, static_cast(dst[4])); - ASSERT_EQ(0x06, static_cast(dst[5])); - ASSERT_EQ(0x07, static_cast(dst[6])); - ASSERT_EQ(0x08, static_cast(dst[7])); -} - -TEST(Coding, Varint32) { - std::string s; - for (uint32_t i = 0; i < (32 * 32); i++) { - uint32_t v = (i / 32) << (i % 32); - PutVarint32(&s, v); - } - - const char* p = s.data(); - const char* limit = p + s.size(); - for (uint32_t i = 0; i < (32 * 32); i++) { - uint32_t expected = (i / 32) << (i % 32); - uint32_t actual; - const char* start = p; - p = GetVarint32Ptr(p, limit, &actual); - ASSERT_TRUE(p != NULL); - ASSERT_EQ(expected, actual); - ASSERT_EQ(VarintLength(actual), p - start); - } - ASSERT_EQ(p, s.data() + s.size()); -} - -TEST(Coding, Varint64) { - // Construct the list of values to check - std::vector values; - // Some special values - values.push_back(0); - values.push_back(100); - values.push_back(~static_cast(0)); - values.push_back(~static_cast(0) - 1); - for (uint32_t k = 0; k < 64; k++) { - // Test values near powers of two - const uint64_t power = 1ull << k; - values.push_back(power); - values.push_back(power-1); - values.push_back(power+1); - }; - - std::string s; - for (int i = 0; i < values.size(); i++) { - PutVarint64(&s, values[i]); - } - - const char* p = s.data(); - const char* limit = p + s.size(); - for (int i = 0; i < values.size(); i++) { - ASSERT_TRUE(p < limit); - uint64_t actual; - const char* start = p; - p = GetVarint64Ptr(p, limit, &actual); - ASSERT_TRUE(p != NULL); - ASSERT_EQ(values[i], actual); - ASSERT_EQ(VarintLength(actual), p - start); - } - ASSERT_EQ(p, limit); - -} - -TEST(Coding, Varint32Overflow) { - uint32_t result; - std::string input("\x81\x82\x83\x84\x85\x11"); - ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result) - == NULL); -} - -TEST(Coding, Varint32Truncation) { - uint32_t large_value = (1u << 31) + 100; - std::string s; - PutVarint32(&s, large_value); - uint32_t result; - for (int len = 0; len < s.size() - 1; len++) { - ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL); - } - ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL); - ASSERT_EQ(large_value, result); -} - -TEST(Coding, Varint64Overflow) { - uint64_t result; - std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11"); - ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result) - == NULL); -} - -TEST(Coding, Varint64Truncation) { - uint64_t large_value = (1ull << 63) + 100ull; - std::string s; - PutVarint64(&s, large_value); - uint64_t result; - for (int len = 0; len < s.size() - 1; len++) { - ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL); - } - ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL); - ASSERT_EQ(large_value, result); -} - -TEST(Coding, Strings) { - std::string s; - PutLengthPrefixedSlice(&s, Slice("")); - PutLengthPrefixedSlice(&s, Slice("foo")); - PutLengthPrefixedSlice(&s, Slice("bar")); - PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x'))); - - Slice input(s); - Slice v; - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ("", v.ToString()); - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ("foo", v.ToString()); - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ("bar", v.ToString()); - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ(std::string(200, 'x'), v.ToString()); - ASSERT_EQ("", input.ToString()); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/comparator.cc b/src/leveldb/util/comparator.cc deleted file mode 100644 index 4b7b5724e..000000000 --- a/src/leveldb/util/comparator.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include "leveldb/comparator.h" -#include "leveldb/slice.h" -#include "port/port.h" -#include "util/logging.h" - -namespace leveldb { - -Comparator::~Comparator() { } - -namespace { -class BytewiseComparatorImpl : public Comparator { - public: - BytewiseComparatorImpl() { } - - virtual const char* Name() const { - return "leveldb.BytewiseComparator"; - } - - virtual int Compare(const Slice& a, const Slice& b) const { - return a.compare(b); - } - - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const { - // Find length of common prefix - size_t min_length = std::min(start->size(), limit.size()); - size_t diff_index = 0; - while ((diff_index < min_length) && - ((*start)[diff_index] == limit[diff_index])) { - diff_index++; - } - - if (diff_index >= min_length) { - // Do not shorten if one string is a prefix of the other - } else { - uint8_t diff_byte = static_cast((*start)[diff_index]); - if (diff_byte < static_cast(0xff) && - diff_byte + 1 < static_cast(limit[diff_index])) { - (*start)[diff_index]++; - start->resize(diff_index + 1); - assert(Compare(*start, limit) < 0); - } - } - } - - virtual void FindShortSuccessor(std::string* key) const { - // Find first character that can be incremented - size_t n = key->size(); - for (size_t i = 0; i < n; i++) { - const uint8_t byte = (*key)[i]; - if (byte != static_cast(0xff)) { - (*key)[i] = byte + 1; - key->resize(i+1); - return; - } - } - // *key is a run of 0xffs. Leave it alone. - } -}; -} // namespace - -static port::OnceType once = LEVELDB_ONCE_INIT; -static const Comparator* bytewise; - -static void InitModule() { - bytewise = new BytewiseComparatorImpl; -} - -const Comparator* BytewiseComparator() { - port::InitOnce(&once, InitModule); - return bytewise; -} - -} // namespace leveldb diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc deleted file mode 100644 index 6db9e7707..000000000 --- a/src/leveldb/util/crc32c.cc +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A portable implementation of crc32c, optimized to handle -// four bytes at a time. - -#include "util/crc32c.h" - -#include -#include "util/coding.h" - -namespace leveldb { -namespace crc32c { - -static const uint32_t table0_[256] = { - 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, - 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, - 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, - 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, - 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, - 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, - 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, - 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, - 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, - 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, - 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, - 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, - 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, - 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, - 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, - 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, - 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, - 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, - 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, - 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, - 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, - 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, - 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, - 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, - 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, - 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, - 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, - 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, - 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, - 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, - 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, - 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, - 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, - 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, - 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, - 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, - 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, - 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, - 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, - 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, - 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, - 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, - 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, - 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, - 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, - 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, - 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, - 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, - 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, - 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, - 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, - 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, - 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, - 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, - 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, - 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, - 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, - 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, - 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, - 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, - 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, - 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, - 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, - 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 -}; -static const uint32_t table1_[256] = { - 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, - 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, - 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, - 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, - 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, - 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, - 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, - 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, - 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, - 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, - 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, - 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, - 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, - 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, - 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, - 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, - 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, - 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, - 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, - 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, - 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, - 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, - 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, - 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, - 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, - 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, - 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, - 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, - 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, - 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, - 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, - 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, - 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, - 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, - 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, - 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, - 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, - 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, - 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, - 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, - 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, - 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, - 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, - 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, - 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, - 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, - 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, - 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, - 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, - 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, - 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, - 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, - 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, - 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, - 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, - 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, - 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, - 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, - 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, - 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, - 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, - 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, - 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, - 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 -}; -static const uint32_t table2_[256] = { - 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, - 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, - 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, - 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, - 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, - 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, - 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, - 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, - 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, - 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, - 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, - 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, - 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, - 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, - 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, - 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, - 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, - 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, - 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, - 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, - 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, - 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, - 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, - 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, - 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, - 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, - 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, - 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, - 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, - 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, - 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, - 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, - 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, - 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, - 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, - 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, - 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, - 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, - 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, - 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, - 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, - 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, - 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, - 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, - 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, - 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, - 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, - 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, - 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, - 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, - 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, - 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, - 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, - 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, - 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, - 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, - 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, - 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, - 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, - 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, - 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, - 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, - 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, - 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 -}; -static const uint32_t table3_[256] = { - 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, - 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, - 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, - 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, - 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, - 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, - 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, - 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, - 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, - 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, - 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, - 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, - 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, - 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, - 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, - 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, - 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, - 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, - 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, - 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, - 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, - 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, - 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, - 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, - 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, - 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, - 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, - 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, - 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, - 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, - 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, - 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, - 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, - 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, - 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, - 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, - 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, - 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, - 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, - 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, - 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, - 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, - 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, - 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, - 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, - 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, - 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, - 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, - 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, - 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, - 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, - 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, - 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, - 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, - 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, - 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, - 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, - 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, - 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, - 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, - 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, - 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, - 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, - 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 -}; - -// Used to fetch a naturally-aligned 32-bit word in little endian byte-order -static inline uint32_t LE_LOAD32(const uint8_t *p) { - return DecodeFixed32(reinterpret_cast(p)); -} - -uint32_t Extend(uint32_t crc, const char* buf, size_t size) { - const uint8_t *p = reinterpret_cast(buf); - const uint8_t *e = p + size; - uint32_t l = crc ^ 0xffffffffu; - -#define STEP1 do { \ - int c = (l & 0xff) ^ *p++; \ - l = table0_[c] ^ (l >> 8); \ -} while (0) -#define STEP4 do { \ - uint32_t c = l ^ LE_LOAD32(p); \ - p += 4; \ - l = table3_[c & 0xff] ^ \ - table2_[(c >> 8) & 0xff] ^ \ - table1_[(c >> 16) & 0xff] ^ \ - table0_[c >> 24]; \ -} while (0) - - // Point x at first 4-byte aligned byte in string. This might be - // just past the end of the string. - const uintptr_t pval = reinterpret_cast(p); - const uint8_t* x = reinterpret_cast(((pval + 3) >> 2) << 2); - if (x <= e) { - // Process bytes until finished or p is 4-byte aligned - while (p != x) { - STEP1; - } - } - // Process bytes 16 at a time - while ((e-p) >= 16) { - STEP4; STEP4; STEP4; STEP4; - } - // Process bytes 4 at a time - while ((e-p) >= 4) { - STEP4; - } - // Process the last few bytes - while (p != e) { - STEP1; - } -#undef STEP4 -#undef STEP1 - return l ^ 0xffffffffu; -} - -} // namespace crc32c -} // namespace leveldb diff --git a/src/leveldb/util/crc32c.h b/src/leveldb/util/crc32c.h deleted file mode 100644 index 1d7e5c075..000000000 --- a/src/leveldb/util/crc32c.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ -#define STORAGE_LEVELDB_UTIL_CRC32C_H_ - -#include -#include - -namespace leveldb { -namespace crc32c { - -// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the -// crc32c of some string A. Extend() is often used to maintain the -// crc32c of a stream of data. -extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); - -// Return the crc32c of data[0,n-1] -inline uint32_t Value(const char* data, size_t n) { - return Extend(0, data, n); -} - -static const uint32_t kMaskDelta = 0xa282ead8ul; - -// Return a masked representation of crc. -// -// Motivation: it is problematic to compute the CRC of a string that -// contains embedded CRCs. Therefore we recommend that CRCs stored -// somewhere (e.g., in files) should be masked before being stored. -inline uint32_t Mask(uint32_t crc) { - // Rotate right by 15 bits and add a constant. - return ((crc >> 15) | (crc << 17)) + kMaskDelta; -} - -// Return the crc whose masked representation is masked_crc. -inline uint32_t Unmask(uint32_t masked_crc) { - uint32_t rot = masked_crc - kMaskDelta; - return ((rot >> 17) | (rot << 15)); -} - -} // namespace crc32c -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/src/leveldb/util/crc32c_test.cc b/src/leveldb/util/crc32c_test.cc deleted file mode 100644 index 4b957ee12..000000000 --- a/src/leveldb/util/crc32c_test.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/crc32c.h" -#include "util/testharness.h" - -namespace leveldb { -namespace crc32c { - -class CRC { }; - -TEST(CRC, StandardResults) { - // From rfc3720 section B.4. - char buf[32]; - - memset(buf, 0, sizeof(buf)); - ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf))); - - memset(buf, 0xff, sizeof(buf)); - ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf))); - - for (int i = 0; i < 32; i++) { - buf[i] = i; - } - ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf))); - - for (int i = 0; i < 32; i++) { - buf[i] = 31 - i; - } - ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf))); - - unsigned char data[48] = { - 0x01, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x18, - 0x28, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - ASSERT_EQ(0xd9963a56, Value(reinterpret_cast(data), sizeof(data))); -} - -TEST(CRC, Values) { - ASSERT_NE(Value("a", 1), Value("foo", 3)); -} - -TEST(CRC, Extend) { - ASSERT_EQ(Value("hello world", 11), - Extend(Value("hello ", 6), "world", 5)); -} - -TEST(CRC, Mask) { - uint32_t crc = Value("foo", 3); - ASSERT_NE(crc, Mask(crc)); - ASSERT_NE(crc, Mask(Mask(crc))); - ASSERT_EQ(crc, Unmask(Mask(crc))); - ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc))))); -} - -} // namespace crc32c -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/env.cc b/src/leveldb/util/env.cc deleted file mode 100644 index c2600e964..000000000 --- a/src/leveldb/util/env.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/env.h" - -namespace leveldb { - -Env::~Env() { -} - -SequentialFile::~SequentialFile() { -} - -RandomAccessFile::~RandomAccessFile() { -} - -WritableFile::~WritableFile() { -} - -Logger::~Logger() { -} - -FileLock::~FileLock() { -} - -void Log(Logger* info_log, const char* format, ...) { - if (info_log != NULL) { - va_list ap; - va_start(ap, format); - info_log->Logv(format, ap); - va_end(ap); - } -} - -static Status DoWriteStringToFile(Env* env, const Slice& data, - const std::string& fname, - bool should_sync) { - WritableFile* file; - Status s = env->NewWritableFile(fname, &file); - if (!s.ok()) { - return s; - } - s = file->Append(data); - if (s.ok() && should_sync) { - s = file->Sync(); - } - if (s.ok()) { - s = file->Close(); - } - delete file; // Will auto-close if we did not close above - if (!s.ok()) { - env->DeleteFile(fname); - } - return s; -} - -Status WriteStringToFile(Env* env, const Slice& data, - const std::string& fname) { - return DoWriteStringToFile(env, data, fname, false); -} - -Status WriteStringToFileSync(Env* env, const Slice& data, - const std::string& fname) { - return DoWriteStringToFile(env, data, fname, true); -} - -Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { - data->clear(); - SequentialFile* file; - Status s = env->NewSequentialFile(fname, &file); - if (!s.ok()) { - return s; - } - static const int kBufferSize = 8192; - char* space = new char[kBufferSize]; - while (true) { - Slice fragment; - s = file->Read(kBufferSize, &fragment, space); - if (!s.ok()) { - break; - } - data->append(fragment.data(), fragment.size()); - if (fragment.empty()) { - break; - } - } - delete[] space; - delete file; - return s; -} - -EnvWrapper::~EnvWrapper() { -} - -} // namespace leveldb diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc deleted file mode 100644 index db81f56d1..000000000 --- a/src/leveldb/util/env_posix.cc +++ /dev/null @@ -1,701 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -#if !defined(LEVELDB_PLATFORM_WINDOWS) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(LEVELDB_PLATFORM_ANDROID) -#include -#endif -#include "leveldb/env.h" -#include "leveldb/slice.h" -#include "port/port.h" -#include "util/logging.h" -#include "util/mutexlock.h" -#include "util/posix_logger.h" - -namespace leveldb { - -namespace { - -static Status IOError(const std::string& context, int err_number) { - return Status::IOError(context, strerror(err_number)); -} - -class PosixSequentialFile: public SequentialFile { - private: - std::string filename_; - FILE* file_; - - public: - PosixSequentialFile(const std::string& fname, FILE* f) - : filename_(fname), file_(f) { } - virtual ~PosixSequentialFile() { fclose(file_); } - - virtual Status Read(size_t n, Slice* result, char* scratch) { - Status s; - size_t r = fread_unlocked(scratch, 1, n, file_); - *result = Slice(scratch, r); - if (r < n) { - if (feof(file_)) { - // We leave status as ok if we hit the end of the file - } else { - // A partial read with an error: return a non-ok status - s = IOError(filename_, errno); - } - } - return s; - } - - virtual Status Skip(uint64_t n) { - if (fseek(file_, n, SEEK_CUR)) { - return IOError(filename_, errno); - } - return Status::OK(); - } -}; - -// pread() based random-access -class PosixRandomAccessFile: public RandomAccessFile { - private: - std::string filename_; - int fd_; - - public: - PosixRandomAccessFile(const std::string& fname, int fd) - : filename_(fname), fd_(fd) { } - virtual ~PosixRandomAccessFile() { close(fd_); } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - Status s; - ssize_t r = pread(fd_, scratch, n, static_cast(offset)); - *result = Slice(scratch, (r < 0) ? 0 : r); - if (r < 0) { - // An error: return a non-ok status - s = IOError(filename_, errno); - } - return s; - } -}; - -// Helper class to limit mmap file usage so that we do not end up -// running out virtual memory or running into kernel performance -// problems for very large databases. -class MmapLimiter { - public: - // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. - MmapLimiter() { - SetAllowed(sizeof(void*) >= 8 ? 1000 : 0); - } - - // If another mmap slot is available, acquire it and return true. - // Else return false. - bool Acquire() { - if (GetAllowed() <= 0) { - return false; - } - MutexLock l(&mu_); - intptr_t x = GetAllowed(); - if (x <= 0) { - return false; - } else { - SetAllowed(x - 1); - return true; - } - } - - // Release a slot acquired by a previous call to Acquire() that returned true. - void Release() { - MutexLock l(&mu_); - SetAllowed(GetAllowed() + 1); - } - - private: - port::Mutex mu_; - port::AtomicPointer allowed_; - - intptr_t GetAllowed() const { - return reinterpret_cast(allowed_.Acquire_Load()); - } - - // REQUIRES: mu_ must be held - void SetAllowed(intptr_t v) { - allowed_.Release_Store(reinterpret_cast(v)); - } - - MmapLimiter(const MmapLimiter&); - void operator=(const MmapLimiter&); -}; - -// mmap() based random-access -class PosixMmapReadableFile: public RandomAccessFile { - private: - std::string filename_; - void* mmapped_region_; - size_t length_; - MmapLimiter* limiter_; - - public: - // base[0,length-1] contains the mmapped contents of the file. - PosixMmapReadableFile(const std::string& fname, void* base, size_t length, - MmapLimiter* limiter) - : filename_(fname), mmapped_region_(base), length_(length), - limiter_(limiter) { - } - - virtual ~PosixMmapReadableFile() { - munmap(mmapped_region_, length_); - limiter_->Release(); - } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - Status s; - if (offset + n > length_) { - *result = Slice(); - s = IOError(filename_, EINVAL); - } else { - *result = Slice(reinterpret_cast(mmapped_region_) + offset, n); - } - return s; - } -}; - -// We preallocate up to an extra megabyte and use memcpy to append new -// data to the file. This is safe since we either properly close the -// file before reading from it, or for log files, the reading code -// knows enough to skip zero suffixes. -class PosixMmapFile : public WritableFile { - private: - std::string filename_; - int fd_; - size_t page_size_; - size_t map_size_; // How much extra memory to map at a time - char* base_; // The mapped region - char* limit_; // Limit of the mapped region - char* dst_; // Where to write next (in range [base_,limit_]) - char* last_sync_; // Where have we synced up to - uint64_t file_offset_; // Offset of base_ in file - - // Have we done an munmap of unsynced data? - bool pending_sync_; - - // Roundup x to a multiple of y - static size_t Roundup(size_t x, size_t y) { - return ((x + y - 1) / y) * y; - } - - size_t TruncateToPageBoundary(size_t s) { - s -= (s & (page_size_ - 1)); - assert((s % page_size_) == 0); - return s; - } - - bool UnmapCurrentRegion() { - bool result = true; - if (base_ != NULL) { - if (last_sync_ < limit_) { - // Defer syncing this data until next Sync() call, if any - pending_sync_ = true; - } - if (munmap(base_, limit_ - base_) != 0) { - result = false; - } - file_offset_ += limit_ - base_; - base_ = NULL; - limit_ = NULL; - last_sync_ = NULL; - dst_ = NULL; - - // Increase the amount we map the next time, but capped at 1MB - if (map_size_ < (1<<20)) { - map_size_ *= 2; - } - } - return result; - } - - bool MapNewRegion() { - assert(base_ == NULL); - if (ftruncate(fd_, file_offset_ + map_size_) < 0) { - return false; - } - void* ptr = mmap(NULL, map_size_, PROT_READ | PROT_WRITE, MAP_SHARED, - fd_, file_offset_); - if (ptr == MAP_FAILED) { - return false; - } - base_ = reinterpret_cast(ptr); - limit_ = base_ + map_size_; - dst_ = base_; - last_sync_ = base_; - return true; - } - - public: - PosixMmapFile(const std::string& fname, int fd, size_t page_size) - : filename_(fname), - fd_(fd), - page_size_(page_size), - map_size_(Roundup(65536, page_size)), - base_(NULL), - limit_(NULL), - dst_(NULL), - last_sync_(NULL), - file_offset_(0), - pending_sync_(false) { - assert((page_size & (page_size - 1)) == 0); - } - - - ~PosixMmapFile() { - if (fd_ >= 0) { - PosixMmapFile::Close(); - } - } - - virtual Status Append(const Slice& data) { - const char* src = data.data(); - size_t left = data.size(); - while (left > 0) { - assert(base_ <= dst_); - assert(dst_ <= limit_); - size_t avail = limit_ - dst_; - if (avail == 0) { - if (!UnmapCurrentRegion() || - !MapNewRegion()) { - return IOError(filename_, errno); - } - } - - size_t n = (left <= avail) ? left : avail; - memcpy(dst_, src, n); - dst_ += n; - src += n; - left -= n; - } - return Status::OK(); - } - - virtual Status Close() { - Status s; - size_t unused = limit_ - dst_; - if (!UnmapCurrentRegion()) { - s = IOError(filename_, errno); - } else if (unused > 0) { - // Trim the extra space at the end of the file - if (ftruncate(fd_, file_offset_ - unused) < 0) { - s = IOError(filename_, errno); - } - } - - if (close(fd_) < 0) { - if (s.ok()) { - s = IOError(filename_, errno); - } - } - - fd_ = -1; - base_ = NULL; - limit_ = NULL; - return s; - } - - virtual Status Flush() { - return Status::OK(); - } - - virtual Status Sync() { - Status s; - - if (pending_sync_) { - // Some unmapped data was not synced - pending_sync_ = false; - if (fdatasync(fd_) < 0) { - s = IOError(filename_, errno); - } - } - - if (dst_ > last_sync_) { - // Find the beginnings of the pages that contain the first and last - // bytes to be synced. - size_t p1 = TruncateToPageBoundary(last_sync_ - base_); - size_t p2 = TruncateToPageBoundary(dst_ - base_ - 1); - last_sync_ = dst_; - if (msync(base_ + p1, p2 - p1 + page_size_, MS_SYNC) < 0) { - s = IOError(filename_, errno); - } - } - - return s; - } -}; - -static int LockOrUnlock(int fd, bool lock) { - errno = 0; - struct flock f; - memset(&f, 0, sizeof(f)); - f.l_type = (lock ? F_WRLCK : F_UNLCK); - f.l_whence = SEEK_SET; - f.l_start = 0; - f.l_len = 0; // Lock/unlock entire file - return fcntl(fd, F_SETLK, &f); -} - -class PosixFileLock : public FileLock { - public: - int fd_; - std::string name_; -}; - -// Set of locked files. We keep a separate set instead of just -// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide -// any protection against multiple uses from the same process. -class PosixLockTable { - private: - port::Mutex mu_; - std::set locked_files_; - public: - bool Insert(const std::string& fname) { - MutexLock l(&mu_); - return locked_files_.insert(fname).second; - } - void Remove(const std::string& fname) { - MutexLock l(&mu_); - locked_files_.erase(fname); - } -}; - -class PosixEnv : public Env { - public: - PosixEnv(); - virtual ~PosixEnv() { - fprintf(stderr, "Destroying Env::Default()\n"); - exit(1); - } - - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result) { - FILE* f = fopen(fname.c_str(), "r"); - if (f == NULL) { - *result = NULL; - return IOError(fname, errno); - } else { - *result = new PosixSequentialFile(fname, f); - return Status::OK(); - } - } - - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) { - *result = NULL; - Status s; - int fd = open(fname.c_str(), O_RDONLY); - if (fd < 0) { - s = IOError(fname, errno); - } else if (mmap_limit_.Acquire()) { - uint64_t size; - s = GetFileSize(fname, &size); - if (s.ok()) { - void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (base != MAP_FAILED) { - *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_); - } else { - s = IOError(fname, errno); - } - } - close(fd); - if (!s.ok()) { - mmap_limit_.Release(); - } - } else { - *result = new PosixRandomAccessFile(fname, fd); - } - return s; - } - - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) { - Status s; - const int fd = open(fname.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644); - if (fd < 0) { - *result = NULL; - s = IOError(fname, errno); - } else { - *result = new PosixMmapFile(fname, fd, page_size_); - } - return s; - } - - virtual bool FileExists(const std::string& fname) { - return access(fname.c_str(), F_OK) == 0; - } - - virtual Status GetChildren(const std::string& dir, - std::vector* result) { - result->clear(); - DIR* d = opendir(dir.c_str()); - if (d == NULL) { - return IOError(dir, errno); - } - struct dirent* entry; - while ((entry = readdir(d)) != NULL) { - result->push_back(entry->d_name); - } - closedir(d); - return Status::OK(); - } - - virtual Status DeleteFile(const std::string& fname) { - Status result; - if (unlink(fname.c_str()) != 0) { - result = IOError(fname, errno); - } - return result; - }; - - virtual Status CreateDir(const std::string& name) { - Status result; - if (mkdir(name.c_str(), 0755) != 0) { - result = IOError(name, errno); - } - return result; - }; - - virtual Status DeleteDir(const std::string& name) { - Status result; - if (rmdir(name.c_str()) != 0) { - result = IOError(name, errno); - } - return result; - }; - - virtual Status GetFileSize(const std::string& fname, uint64_t* size) { - Status s; - struct stat sbuf; - if (stat(fname.c_str(), &sbuf) != 0) { - *size = 0; - s = IOError(fname, errno); - } else { - *size = sbuf.st_size; - } - return s; - } - - virtual Status RenameFile(const std::string& src, const std::string& target) { - Status result; - if (rename(src.c_str(), target.c_str()) != 0) { - result = IOError(src, errno); - } - return result; - } - - virtual Status LockFile(const std::string& fname, FileLock** lock) { - *lock = NULL; - Status result; - int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644); - if (fd < 0) { - result = IOError(fname, errno); - } else if (!locks_.Insert(fname)) { - close(fd); - result = Status::IOError("lock " + fname, "already held by process"); - } else if (LockOrUnlock(fd, true) == -1) { - result = IOError("lock " + fname, errno); - close(fd); - locks_.Remove(fname); - } else { - PosixFileLock* my_lock = new PosixFileLock; - my_lock->fd_ = fd; - my_lock->name_ = fname; - *lock = my_lock; - } - return result; - } - - virtual Status UnlockFile(FileLock* lock) { - PosixFileLock* my_lock = reinterpret_cast(lock); - Status result; - if (LockOrUnlock(my_lock->fd_, false) == -1) { - result = IOError("unlock", errno); - } - locks_.Remove(my_lock->name_); - close(my_lock->fd_); - delete my_lock; - return result; - } - - virtual void Schedule(void (*function)(void*), void* arg); - - virtual void StartThread(void (*function)(void* arg), void* arg); - - virtual Status GetTestDirectory(std::string* result) { - const char* env = getenv("TEST_TMPDIR"); - if (env && env[0] != '\0') { - *result = env; - } else { - char buf[100]; - snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); - *result = buf; - } - // Directory may already exist - CreateDir(*result); - return Status::OK(); - } - - static uint64_t gettid() { - pthread_t tid = pthread_self(); - uint64_t thread_id = 0; - memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); - return thread_id; - } - - virtual Status NewLogger(const std::string& fname, Logger** result) { - FILE* f = fopen(fname.c_str(), "w"); - if (f == NULL) { - *result = NULL; - return IOError(fname, errno); - } else { - *result = new PosixLogger(f, &PosixEnv::gettid); - return Status::OK(); - } - } - - virtual uint64_t NowMicros() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; - } - - virtual void SleepForMicroseconds(int micros) { - usleep(micros); - } - - private: - void PthreadCall(const char* label, int result) { - if (result != 0) { - fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - exit(1); - } - } - - // BGThread() is the body of the background thread - void BGThread(); - static void* BGThreadWrapper(void* arg) { - reinterpret_cast(arg)->BGThread(); - return NULL; - } - - size_t page_size_; - pthread_mutex_t mu_; - pthread_cond_t bgsignal_; - pthread_t bgthread_; - bool started_bgthread_; - - // Entry per Schedule() call - struct BGItem { void* arg; void (*function)(void*); }; - typedef std::deque BGQueue; - BGQueue queue_; - - PosixLockTable locks_; - MmapLimiter mmap_limit_; -}; - -PosixEnv::PosixEnv() : page_size_(getpagesize()), - started_bgthread_(false) { - PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); - PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); -} - -void PosixEnv::Schedule(void (*function)(void*), void* arg) { - PthreadCall("lock", pthread_mutex_lock(&mu_)); - - // Start background thread if necessary - if (!started_bgthread_) { - started_bgthread_ = true; - PthreadCall( - "create thread", - pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this)); - } - - // If the queue is currently empty, the background thread may currently be - // waiting. - if (queue_.empty()) { - PthreadCall("signal", pthread_cond_signal(&bgsignal_)); - } - - // Add to priority queue - queue_.push_back(BGItem()); - queue_.back().function = function; - queue_.back().arg = arg; - - PthreadCall("unlock", pthread_mutex_unlock(&mu_)); -} - -void PosixEnv::BGThread() { - while (true) { - // Wait until there is an item that is ready to run - PthreadCall("lock", pthread_mutex_lock(&mu_)); - while (queue_.empty()) { - PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_)); - } - - void (*function)(void*) = queue_.front().function; - void* arg = queue_.front().arg; - queue_.pop_front(); - - PthreadCall("unlock", pthread_mutex_unlock(&mu_)); - (*function)(arg); - } -} - -namespace { -struct StartThreadState { - void (*user_function)(void*); - void* arg; -}; -} -static void* StartThreadWrapper(void* arg) { - StartThreadState* state = reinterpret_cast(arg); - state->user_function(state->arg); - delete state; - return NULL; -} - -void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { - pthread_t t; - StartThreadState* state = new StartThreadState; - state->user_function = function; - state->arg = arg; - PthreadCall("start thread", - pthread_create(&t, NULL, &StartThreadWrapper, state)); -} - -} // namespace - -static pthread_once_t once = PTHREAD_ONCE_INIT; -static Env* default_env; -static void InitDefaultEnv() { default_env = new PosixEnv; } - -Env* Env::Default() { - pthread_once(&once, InitDefaultEnv); - return default_env; -} - -} // namespace leveldb - -#endif diff --git a/src/leveldb/util/env_test.cc b/src/leveldb/util/env_test.cc deleted file mode 100644 index b72cb4438..000000000 --- a/src/leveldb/util/env_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/env.h" - -#include "port/port.h" -#include "util/testharness.h" - -namespace leveldb { - -static const int kDelayMicros = 100000; - -class EnvPosixTest { - private: - port::Mutex mu_; - std::string events_; - - public: - Env* env_; - EnvPosixTest() : env_(Env::Default()) { } -}; - -static void SetBool(void* ptr) { - reinterpret_cast(ptr)->NoBarrier_Store(ptr); -} - -TEST(EnvPosixTest, RunImmediately) { - port::AtomicPointer called (NULL); - env_->Schedule(&SetBool, &called); - Env::Default()->SleepForMicroseconds(kDelayMicros); - ASSERT_TRUE(called.NoBarrier_Load() != NULL); -} - -TEST(EnvPosixTest, RunMany) { - port::AtomicPointer last_id (NULL); - - struct CB { - port::AtomicPointer* last_id_ptr; // Pointer to shared slot - uintptr_t id; // Order# for the execution of this callback - - CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } - - static void Run(void* v) { - CB* cb = reinterpret_cast(v); - void* cur = cb->last_id_ptr->NoBarrier_Load(); - ASSERT_EQ(cb->id-1, reinterpret_cast(cur)); - cb->last_id_ptr->Release_Store(reinterpret_cast(cb->id)); - } - }; - - // Schedule in different order than start time - CB cb1(&last_id, 1); - CB cb2(&last_id, 2); - CB cb3(&last_id, 3); - CB cb4(&last_id, 4); - env_->Schedule(&CB::Run, &cb1); - env_->Schedule(&CB::Run, &cb2); - env_->Schedule(&CB::Run, &cb3); - env_->Schedule(&CB::Run, &cb4); - - Env::Default()->SleepForMicroseconds(kDelayMicros); - void* cur = last_id.Acquire_Load(); - ASSERT_EQ(4, reinterpret_cast(cur)); -} - -struct State { - port::Mutex mu; - int val; - int num_running; -}; - -static void ThreadBody(void* arg) { - State* s = reinterpret_cast(arg); - s->mu.Lock(); - s->val += 1; - s->num_running -= 1; - s->mu.Unlock(); -} - -TEST(EnvPosixTest, StartThread) { - State state; - state.val = 0; - state.num_running = 3; - for (int i = 0; i < 3; i++) { - env_->StartThread(&ThreadBody, &state); - } - while (true) { - state.mu.Lock(); - int num = state.num_running; - state.mu.Unlock(); - if (num == 0) { - break; - } - Env::Default()->SleepForMicroseconds(kDelayMicros); - } - ASSERT_EQ(state.val, 3); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc deleted file mode 100644 index ef2ecae83..000000000 --- a/src/leveldb/util/env_win.cc +++ /dev/null @@ -1,1031 +0,0 @@ -// This file contains source that originates from: -// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h -// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc -// Those files dont' have any explict license headers but the -// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' -// as the license. -#if defined(LEVELDB_PLATFORM_WINDOWS) -#include - - -#include "leveldb/env.h" - -#include "port/port.h" -#include "leveldb/slice.h" -#include "util/logging.h" - -#include -#include -#include -#include -#include -#include -#include - -#ifdef max -#undef max -#endif - -#ifndef va_copy -#define va_copy(d,s) ((d) = (s)) -#endif - -#if defined DeleteFile -#undef DeleteFile -#endif - -//Declarations -namespace leveldb -{ - -namespace Win32 -{ - -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -std::string GetCurrentDir(); -std::wstring GetCurrentDirW(); - -static const std::string CurrentDir = GetCurrentDir(); -static const std::wstring CurrentDirW = GetCurrentDirW(); - -std::string& ModifyPath(std::string& path); -std::wstring& ModifyPath(std::wstring& path); - -std::string GetLastErrSz(); -std::wstring GetLastErrSzW(); - -size_t GetPageSize(); - -typedef void (*ScheduleProc)(void*) ; - -struct WorkItemWrapper -{ - WorkItemWrapper(ScheduleProc proc_,void* content_); - ScheduleProc proc; - void* pContent; -}; - -DWORD WINAPI WorkItemWrapperProc(LPVOID pContent); - -class Win32SequentialFile : public SequentialFile -{ -public: - friend class Win32Env; - virtual ~Win32SequentialFile(); - virtual Status Read(size_t n, Slice* result, char* scratch); - virtual Status Skip(uint64_t n); - BOOL isEnable(); -private: - BOOL _Init(); - void _CleanUp(); - Win32SequentialFile(const std::string& fname); - std::string _filename; - ::HANDLE _hFile; - DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile); -}; - -class Win32RandomAccessFile : public RandomAccessFile -{ -public: - friend class Win32Env; - virtual ~Win32RandomAccessFile(); - virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; - BOOL isEnable(); -private: - BOOL _Init(LPCWSTR path); - void _CleanUp(); - Win32RandomAccessFile(const std::string& fname); - HANDLE _hFile; - const std::string _filename; - DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); -}; - -class Win32MapFile : public WritableFile -{ -public: - Win32MapFile(const std::string& fname); - - ~Win32MapFile(); - virtual Status Append(const Slice& data); - virtual Status Close(); - virtual Status Flush(); - virtual Status Sync(); - BOOL isEnable(); -private: - std::string _filename; - HANDLE _hFile; - size_t _page_size; - size_t _map_size; // How much extra memory to map at a time - char* _base; // The mapped region - HANDLE _base_handle; - char* _limit; // Limit of the mapped region - char* _dst; // Where to write next (in range [base_,limit_]) - char* _last_sync; // Where have we synced up to - uint64_t _file_offset; // Offset of base_ in file - //LARGE_INTEGER file_offset_; - // Have we done an munmap of unsynced data? - bool _pending_sync; - - // Roundup x to a multiple of y - static size_t _Roundup(size_t x, size_t y); - size_t _TruncateToPageBoundary(size_t s); - bool _UnmapCurrentRegion(); - bool _MapNewRegion(); - DISALLOW_COPY_AND_ASSIGN(Win32MapFile); - BOOL _Init(LPCWSTR Path); -}; - -class Win32FileLock : public FileLock -{ -public: - friend class Win32Env; - virtual ~Win32FileLock(); - BOOL isEnable(); -private: - BOOL _Init(LPCWSTR path); - void _CleanUp(); - Win32FileLock(const std::string& fname); - HANDLE _hFile; - std::string _filename; - DISALLOW_COPY_AND_ASSIGN(Win32FileLock); -}; - -class Win32Logger : public Logger -{ -public: - friend class Win32Env; - virtual ~Win32Logger(); - virtual void Logv(const char* format, va_list ap); -private: - explicit Win32Logger(WritableFile* pFile); - WritableFile* _pFileProxy; - DISALLOW_COPY_AND_ASSIGN(Win32Logger); -}; - -class Win32Env : public Env -{ -public: - Win32Env(); - virtual ~Win32Env(); - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result); - - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result); - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result); - - virtual bool FileExists(const std::string& fname); - - virtual Status GetChildren(const std::string& dir, - std::vector* result); - - virtual Status DeleteFile(const std::string& fname); - - virtual Status CreateDir(const std::string& dirname); - - virtual Status DeleteDir(const std::string& dirname); - - virtual Status GetFileSize(const std::string& fname, uint64_t* file_size); - - virtual Status RenameFile(const std::string& src, - const std::string& target); - - virtual Status LockFile(const std::string& fname, FileLock** lock); - - virtual Status UnlockFile(FileLock* lock); - - virtual void Schedule( - void (*function)(void* arg), - void* arg); - - virtual void StartThread(void (*function)(void* arg), void* arg); - - virtual Status GetTestDirectory(std::string* path); - - //virtual void Logv(WritableFile* log, const char* format, va_list ap); - - virtual Status NewLogger(const std::string& fname, Logger** result); - - virtual uint64_t NowMicros(); - - virtual void SleepForMicroseconds(int micros); -}; - -void ToWidePath(const std::string& value, std::wstring& target) { - wchar_t buffer[MAX_PATH]; - MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); - target = buffer; -} - -void ToNarrowPath(const std::wstring& value, std::string& target) { - char buffer[MAX_PATH]; - WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); - target = buffer; -} - -std::string GetCurrentDir() -{ - CHAR path[MAX_PATH]; - ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); - *strrchr(path,'\\') = 0; - return std::string(path); -} - -std::wstring GetCurrentDirW() -{ - WCHAR path[MAX_PATH]; - ::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH); - *wcsrchr(path,L'\\') = 0; - return std::wstring(path); -} - -std::string& ModifyPath(std::string& path) -{ - if(path[0] == '/' || path[0] == '\\'){ - path = CurrentDir + path; - } - std::replace(path.begin(),path.end(),'/','\\'); - - return path; -} - -std::wstring& ModifyPath(std::wstring& path) -{ - if(path[0] == L'/' || path[0] == L'\\'){ - path = CurrentDirW + path; - } - std::replace(path.begin(),path.end(),L'/',L'\\'); - return path; -} - -std::string GetLastErrSz() -{ - LPWSTR lpMsgBuf; - FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - 0, // Default language - (LPWSTR) &lpMsgBuf, - 0, - NULL - ); - std::string Err; - ToNarrowPath(lpMsgBuf, Err); - LocalFree( lpMsgBuf ); - return Err; -} - -std::wstring GetLastErrSzW() -{ - LPVOID lpMsgBuf; - FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - 0, // Default language - (LPWSTR) &lpMsgBuf, - 0, - NULL - ); - std::wstring Err = (LPCWSTR)lpMsgBuf; - LocalFree(lpMsgBuf); - return Err; -} - -WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) : - proc(proc_),pContent(content_) -{ - -} - -DWORD WINAPI WorkItemWrapperProc(LPVOID pContent) -{ - WorkItemWrapper* item = static_cast(pContent); - ScheduleProc TempProc = item->proc; - void* arg = item->pContent; - delete item; - TempProc(arg); - return 0; -} - -size_t GetPageSize() -{ - SYSTEM_INFO si; - GetSystemInfo(&si); - return std::max(si.dwPageSize,si.dwAllocationGranularity); -} - -const size_t g_PageSize = GetPageSize(); - - -Win32SequentialFile::Win32SequentialFile( const std::string& fname ) : - _filename(fname),_hFile(NULL) -{ - _Init(); -} - -Win32SequentialFile::~Win32SequentialFile() -{ - _CleanUp(); -} - -Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch ) -{ - Status sRet; - DWORD hasRead = 0; - if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){ - *result = Slice(scratch,hasRead); - } else { - sRet = Status::IOError(_filename, Win32::GetLastErrSz() ); - } - return sRet; -} - -Status Win32SequentialFile::Skip( uint64_t n ) -{ - Status sRet; - LARGE_INTEGER Move,NowPointer; - Move.QuadPart = n; - if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){ - sRet = Status::IOError(_filename,Win32::GetLastErrSz()); - } - return sRet; -} - -BOOL Win32SequentialFile::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -BOOL Win32SequentialFile::_Init() -{ - std::wstring path; - ToWidePath(_filename, path); - _hFile = CreateFileW(path.c_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - return _hFile ? TRUE : FALSE; -} - -void Win32SequentialFile::_CleanUp() -{ - if(_hFile){ - CloseHandle(_hFile); - _hFile = NULL; - } -} - -Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) : - _filename(fname),_hFile(NULL) -{ - std::wstring path; - ToWidePath(fname, path); - _Init( path.c_str() ); -} - -Win32RandomAccessFile::~Win32RandomAccessFile() -{ - _CleanUp(); -} - -Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const -{ - Status sRet; - OVERLAPPED ol = {0}; - ZeroMemory(&ol,sizeof(ol)); - ol.Offset = (DWORD)offset; - ol.OffsetHigh = (DWORD)(offset >> 32); - DWORD hasRead = 0; - if(!ReadFile(_hFile,scratch,n,&hasRead,&ol)) - sRet = Status::IOError(_filename,Win32::GetLastErrSz()); - else - *result = Slice(scratch,hasRead); - return sRet; -} - -BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) -{ - BOOL bRet = FALSE; - if(!_hFile) - _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) - _hFile = NULL; - else - bRet = TRUE; - return bRet; -} - -BOOL Win32RandomAccessFile::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -void Win32RandomAccessFile::_CleanUp() -{ - if(_hFile){ - ::CloseHandle(_hFile); - _hFile = NULL; - } -} - -size_t Win32MapFile::_Roundup( size_t x, size_t y ) -{ - return ((x + y - 1) / y) * y; -} - -size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) -{ - s -= (s & (_page_size - 1)); - assert((s % _page_size) == 0); - return s; -} - -bool Win32MapFile::_UnmapCurrentRegion() -{ - bool result = true; - if (_base != NULL) { - if (_last_sync < _limit) { - // Defer syncing this data until next Sync() call, if any - _pending_sync = true; - } - if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) - result = false; - _file_offset += _limit - _base; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - _last_sync = NULL; - _dst = NULL; - // Increase the amount we map the next time, but capped at 1MB - if (_map_size < (1<<20)) { - _map_size *= 2; - } - } - return result; -} - -bool Win32MapFile::_MapNewRegion() -{ - assert(_base == NULL); - //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); - //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); - DWORD off_hi = (DWORD)(_file_offset >> 32); - DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset + _map_size; - SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); - SetEndOfFile(_hFile); - - _base_handle = CreateFileMappingA( - _hFile, - NULL, - PAGE_READWRITE, - 0, - 0, - 0); - if (_base_handle != NULL) { - _base = (char*) MapViewOfFile(_base_handle, - FILE_MAP_ALL_ACCESS, - off_hi, - off_lo, - _map_size); - if (_base != NULL) { - _limit = _base + _map_size; - _dst = _base; - _last_sync = _base; - return true; - } - } - return false; -} - -Win32MapFile::Win32MapFile( const std::string& fname) : - _filename(fname), - _hFile(NULL), - _page_size(Win32::g_PageSize), - _map_size(_Roundup(65536, Win32::g_PageSize)), - _base(NULL), - _base_handle(NULL), - _limit(NULL), - _dst(NULL), - _last_sync(NULL), - _file_offset(0), - _pending_sync(false) -{ - std::wstring path; - ToWidePath(fname, path); - _Init(path.c_str()); - assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); -} - -Status Win32MapFile::Append( const Slice& data ) -{ - const char* src = data.data(); - size_t left = data.size(); - Status s; - while (left > 0) { - assert(_base <= _dst); - assert(_dst <= _limit); - size_t avail = _limit - _dst; - if (avail == 0) { - if (!_UnmapCurrentRegion() || - !_MapNewRegion()) { - return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); - } - } - size_t n = (left <= avail) ? left : avail; - memcpy(_dst, src, n); - _dst += n; - src += n; - left -= n; - } - return s; -} - -Status Win32MapFile::Close() -{ - Status s; - size_t unused = _limit - _dst; - if (!_UnmapCurrentRegion()) { - s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); - } else if (unused > 0) { - // Trim the extra space at the end of the file - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset - unused; - if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { - s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); - } else - SetEndOfFile(_hFile); - } - if (!CloseHandle(_hFile)) { - if (s.ok()) { - s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); - } - } - _hFile = INVALID_HANDLE_VALUE; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - - return s; -} - -Status Win32MapFile::Sync() -{ - Status s; - if (_pending_sync) { - // Some unmapped data was not synced - _pending_sync = false; - if (!FlushFileBuffers(_hFile)) { - s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); - } - } - if (_dst > _last_sync) { - // Find the beginnings of the pages that contain the first and last - // bytes to be synced. - size_t p1 = _TruncateToPageBoundary(_last_sync - _base); - size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); - _last_sync = _dst; - if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { - s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); - } - } - return s; -} - -Status Win32MapFile::Flush() -{ - return Status::OK(); -} - -Win32MapFile::~Win32MapFile() -{ - if (_hFile != INVALID_HANDLE_VALUE) { - Win32MapFile::Close(); - } -} - -BOOL Win32MapFile::_Init( LPCWSTR Path ) -{ - DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; - _hFile = CreateFileW(Path, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, - NULL, - Flag, - FILE_ATTRIBUTE_NORMAL, - NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE) - return FALSE; - else - return TRUE; -} - -BOOL Win32MapFile::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -Win32FileLock::Win32FileLock( const std::string& fname ) : - _hFile(NULL),_filename(fname) -{ - std::wstring path; - ToWidePath(fname, path); - _Init(path.c_str()); -} - -Win32FileLock::~Win32FileLock() -{ - _CleanUp(); -} - -BOOL Win32FileLock::_Init( LPCWSTR path ) -{ - BOOL bRet = FALSE; - if(!_hFile) - _hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){ - _hFile = NULL; - } - else - bRet = TRUE; - return bRet; -} - -void Win32FileLock::_CleanUp() -{ - ::CloseHandle(_hFile); - _hFile = NULL; -} - -BOOL Win32FileLock::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile) -{ - assert(_pFileProxy); -} - -Win32Logger::~Win32Logger() -{ - if(_pFileProxy) - delete _pFileProxy; -} - -void Win32Logger::Logv( const char* format, va_list ap ) -{ - uint64_t thread_id = ::GetCurrentThreadId(); - - // We try twice: the first time with a fixed-size stack allocated buffer, - // and the second time with a much larger dynamically allocated buffer. - char buffer[500]; - for (int iter = 0; iter < 2; iter++) { - char* base; - int bufsize; - if (iter == 0) { - bufsize = sizeof(buffer); - base = buffer; - } else { - bufsize = 30000; - base = new char[bufsize]; - } - char* p = base; - char* limit = base + bufsize; - - SYSTEMTIME st; - GetLocalTime(&st); - p += snprintf(p, limit - p, - "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", - int(st.wYear), - int(st.wMonth), - int(st.wDay), - int(st.wHour), - int(st.wMinute), - int(st.wMinute), - int(st.wMilliseconds), - static_cast(thread_id)); - - // Print the message - if (p < limit) { - va_list backup_ap; - va_copy(backup_ap, ap); - p += vsnprintf(p, limit - p, format, backup_ap); - va_end(backup_ap); - } - - // Truncate to available space if necessary - if (p >= limit) { - if (iter == 0) { - continue; // Try again with larger buffer - } else { - p = limit - 1; - } - } - - // Add newline if necessary - if (p == base || p[-1] != '\n') { - *p++ = '\n'; - } - - assert(p <= limit); - DWORD hasWritten = 0; - if(_pFileProxy){ - _pFileProxy->Append(Slice(base, p - base)); - _pFileProxy->Flush(); - } - if (base != buffer) { - delete[] base; - } - break; - } -} - -bool Win32Env::FileExists(const std::string& fname) -{ - std::string path = fname; - std::wstring wpath; - ToWidePath(ModifyPath(path), wpath); - return ::PathFileExistsW(wpath.c_str()) ? true : false; -} - -Status Win32Env::GetChildren(const std::string& dir, std::vector* result) -{ - Status sRet; - ::WIN32_FIND_DATAW wfd; - std::string path = dir; - ModifyPath(path); - path += "\\*.*"; - std::wstring wpath; - ToWidePath(path, wpath); - - ::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd); - if(hFind && hFind != INVALID_HANDLE_VALUE){ - BOOL hasNext = TRUE; - std::string child; - while(hasNext){ - ToNarrowPath(wfd.cFileName, child); - if(child != ".." && child != ".") { - result->push_back(child); - } - hasNext = ::FindNextFileW(hFind,&wfd); - } - ::FindClose(hFind); - } - else - sRet = Status::IOError(dir,"Could not get children."); - return sRet; -} - -void Win32Env::SleepForMicroseconds( int micros ) -{ - ::Sleep((micros + 999) /1000); -} - - -Status Win32Env::DeleteFile( const std::string& fname ) -{ - Status sRet; - std::string path = fname; - std::wstring wpath; - ToWidePath(ModifyPath(path), wpath); - - if(!::DeleteFileW(wpath.c_str())) { - sRet = Status::IOError(path, "Could not delete file."); - } - return sRet; -} - -Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) -{ - Status sRet; - std::string path = fname; - std::wstring wpath; - ToWidePath(ModifyPath(path), wpath); - - HANDLE file = ::CreateFileW(wpath.c_str(), - GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); - LARGE_INTEGER li; - if(::GetFileSizeEx(file,&li)){ - *file_size = (uint64_t)li.QuadPart; - }else - sRet = Status::IOError(path,"Could not get the file size."); - CloseHandle(file); - return sRet; -} - -Status Win32Env::RenameFile( const std::string& src, const std::string& target ) -{ - Status sRet; - std::string src_path = src; - std::wstring wsrc_path; - ToWidePath(ModifyPath(src_path), wsrc_path); - std::string target_path = target; - std::wstring wtarget_path; - ToWidePath(ModifyPath(target_path), wtarget_path); - - if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){ - DWORD err = GetLastError(); - if(err == 0x000000b7){ - if(!::DeleteFileW(wtarget_path.c_str() ) ) - sRet = Status::IOError(src, "Could not rename file."); - else if(!::MoveFileW(wsrc_path.c_str(), - wtarget_path.c_str() ) ) - sRet = Status::IOError(src, "Could not rename file."); - } - } - return sRet; -} - -Status Win32Env::LockFile( const std::string& fname, FileLock** lock ) -{ - Status sRet; - std::string path = fname; - ModifyPath(path); - Win32FileLock* _lock = new Win32FileLock(path); - if(!_lock->isEnable()){ - delete _lock; - *lock = NULL; - sRet = Status::IOError(path, "Could not lock file."); - } - else - *lock = _lock; - return sRet; -} - -Status Win32Env::UnlockFile( FileLock* lock ) -{ - Status sRet; - delete lock; - return sRet; -} - -void Win32Env::Schedule( void (*function)(void* arg), void* arg ) -{ - QueueUserWorkItem(Win32::WorkItemWrapperProc, - new Win32::WorkItemWrapper(function,arg), - WT_EXECUTEDEFAULT); -} - -void Win32Env::StartThread( void (*function)(void* arg), void* arg ) -{ - ::_beginthread(function,0,arg); -} - -Status Win32Env::GetTestDirectory( std::string* path ) -{ - Status sRet; - WCHAR TempPath[MAX_PATH]; - ::GetTempPathW(MAX_PATH,TempPath); - ToNarrowPath(TempPath, *path); - path->append("leveldb\\test\\"); - ModifyPath(*path); - return sRet; -} - -uint64_t Win32Env::NowMicros() -{ -#ifndef USE_VISTA_API -#define GetTickCount64 GetTickCount -#endif - return (uint64_t)(GetTickCount64()*1000); -} - -static Status CreateDirInner( const std::string& dirname ) -{ - Status sRet; - DWORD attr = ::GetFileAttributes(dirname.c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: - std::size_t slash = dirname.find_last_of("\\"); - if (slash != std::string::npos){ - sRet = CreateDirInner(dirname.substr(0, slash)); - if (!sRet.ok()) return sRet; - } - BOOL result = ::CreateDirectory(dirname.c_str(), NULL); - if (result == FALSE) { - sRet = Status::IOError(dirname, "Could not create directory."); - return sRet; - } - } - return sRet; -} - -Status Win32Env::CreateDir( const std::string& dirname ) -{ - std::string path = dirname; - if(path[path.length() - 1] != '\\'){ - path += '\\'; - } - ModifyPath(path); - - return CreateDirInner(path); -} - -Status Win32Env::DeleteDir( const std::string& dirname ) -{ - Status sRet; - std::wstring path; - ToWidePath(dirname, path); - ModifyPath(path); - if(!::RemoveDirectoryW( path.c_str() ) ){ - sRet = Status::IOError(dirname, "Could not delete directory."); - } - return sRet; -} - -Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result ) -{ - Status sRet; - std::string path = fname; - ModifyPath(path); - Win32SequentialFile* pFile = new Win32SequentialFile(path); - if(pFile->isEnable()){ - *result = pFile; - }else { - delete pFile; - sRet = Status::IOError(path, Win32::GetLastErrSz()); - } - return sRet; -} - -Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result ) -{ - Status sRet; - std::string path = fname; - Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path)); - if(!pFile->isEnable()){ - delete pFile; - *result = NULL; - sRet = Status::IOError(path, Win32::GetLastErrSz()); - }else - *result = pFile; - return sRet; -} - -Status Win32Env::NewLogger( const std::string& fname, Logger** result ) -{ - Status sRet; - std::string path = fname; - Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); - if(!pMapFile->isEnable()){ - delete pMapFile; - *result = NULL; - sRet = Status::IOError(path,"could not create a logger."); - }else - *result = new Win32Logger(pMapFile); - return sRet; -} - -Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result ) -{ - Status sRet; - std::string path = fname; - Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); - if(!pFile->isEnable()){ - *result = NULL; - sRet = Status::IOError(fname,Win32::GetLastErrSz()); - }else - *result = pFile; - return sRet; -} - -Win32Env::Win32Env() -{ - -} - -Win32Env::~Win32Env() -{ - -} - - -} // Win32 namespace - -static port::OnceType once = LEVELDB_ONCE_INIT; -static Env* default_env; -static void InitDefaultEnv() { default_env = new Win32::Win32Env(); } - -Env* Env::Default() { - port::InitOnce(&once, InitDefaultEnv); - return default_env; -} - -} // namespace leveldb - -#endif // defined(LEVELDB_PLATFORM_WINDOWS) diff --git a/src/leveldb/util/filter_policy.cc b/src/leveldb/util/filter_policy.cc deleted file mode 100644 index 7b045c8c9..000000000 --- a/src/leveldb/util/filter_policy.cc +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/filter_policy.h" - -namespace leveldb { - -FilterPolicy::~FilterPolicy() { } - -} // namespace leveldb diff --git a/src/leveldb/util/hash.cc b/src/leveldb/util/hash.cc deleted file mode 100644 index ba1818082..000000000 --- a/src/leveldb/util/hash.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "util/coding.h" -#include "util/hash.h" - -namespace leveldb { - -uint32_t Hash(const char* data, size_t n, uint32_t seed) { - // Similar to murmur hash - const uint32_t m = 0xc6a4a793; - const uint32_t r = 24; - const char* limit = data + n; - uint32_t h = seed ^ (n * m); - - // Pick up four bytes at a time - while (data + 4 <= limit) { - uint32_t w = DecodeFixed32(data); - data += 4; - h += w; - h *= m; - h ^= (h >> 16); - } - - // Pick up remaining bytes - switch (limit - data) { - case 3: - h += data[2] << 16; - // fall through - case 2: - h += data[1] << 8; - // fall through - case 1: - h += data[0]; - h *= m; - h ^= (h >> r); - break; - } - return h; -} - - -} // namespace leveldb diff --git a/src/leveldb/util/hash.h b/src/leveldb/util/hash.h deleted file mode 100644 index 8889d56be..000000000 --- a/src/leveldb/util/hash.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Simple hash function used for internal data structures - -#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ -#define STORAGE_LEVELDB_UTIL_HASH_H_ - -#include -#include - -namespace leveldb { - -extern uint32_t Hash(const char* data, size_t n, uint32_t seed); - -} - -#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/src/leveldb/util/histogram.cc b/src/leveldb/util/histogram.cc deleted file mode 100644 index bb95f583e..000000000 --- a/src/leveldb/util/histogram.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include "port/port.h" -#include "util/histogram.h" - -namespace leveldb { - -const double Histogram::kBucketLimit[kNumBuckets] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, - 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450, - 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000, - 3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, - 16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000, - 70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000, - 250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000, - 900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000, - 3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000, - 9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000, - 25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000, - 70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000, - 180000000, 200000000, 250000000, 300000000, 350000000, 400000000, - 450000000, 500000000, 600000000, 700000000, 800000000, 900000000, - 1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000, - 2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0, - 5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0, - 1e200, -}; - -void Histogram::Clear() { - min_ = kBucketLimit[kNumBuckets-1]; - max_ = 0; - num_ = 0; - sum_ = 0; - sum_squares_ = 0; - for (int i = 0; i < kNumBuckets; i++) { - buckets_[i] = 0; - } -} - -void Histogram::Add(double value) { - // Linear search is fast enough for our usage in db_bench - int b = 0; - while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { - b++; - } - buckets_[b] += 1.0; - if (min_ > value) min_ = value; - if (max_ < value) max_ = value; - num_++; - sum_ += value; - sum_squares_ += (value * value); -} - -void Histogram::Merge(const Histogram& other) { - if (other.min_ < min_) min_ = other.min_; - if (other.max_ > max_) max_ = other.max_; - num_ += other.num_; - sum_ += other.sum_; - sum_squares_ += other.sum_squares_; - for (int b = 0; b < kNumBuckets; b++) { - buckets_[b] += other.buckets_[b]; - } -} - -double Histogram::Median() const { - return Percentile(50.0); -} - -double Histogram::Percentile(double p) const { - double threshold = num_ * (p / 100.0); - double sum = 0; - for (int b = 0; b < kNumBuckets; b++) { - sum += buckets_[b]; - if (sum >= threshold) { - // Scale linearly within this bucket - double left_point = (b == 0) ? 0 : kBucketLimit[b-1]; - double right_point = kBucketLimit[b]; - double left_sum = sum - buckets_[b]; - double right_sum = sum; - double pos = (threshold - left_sum) / (right_sum - left_sum); - double r = left_point + (right_point - left_point) * pos; - if (r < min_) r = min_; - if (r > max_) r = max_; - return r; - } - } - return max_; -} - -double Histogram::Average() const { - if (num_ == 0.0) return 0; - return sum_ / num_; -} - -double Histogram::StandardDeviation() const { - if (num_ == 0.0) return 0; - double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); - return sqrt(variance); -} - -std::string Histogram::ToString() const { - std::string r; - char buf[200]; - snprintf(buf, sizeof(buf), - "Count: %.0f Average: %.4f StdDev: %.2f\n", - num_, Average(), StandardDeviation()); - r.append(buf); - snprintf(buf, sizeof(buf), - "Min: %.4f Median: %.4f Max: %.4f\n", - (num_ == 0.0 ? 0.0 : min_), Median(), max_); - r.append(buf); - r.append("------------------------------------------------------\n"); - const double mult = 100.0 / num_; - double sum = 0; - for (int b = 0; b < kNumBuckets; b++) { - if (buckets_[b] <= 0.0) continue; - sum += buckets_[b]; - snprintf(buf, sizeof(buf), - "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", - ((b == 0) ? 0.0 : kBucketLimit[b-1]), // left - kBucketLimit[b], // right - buckets_[b], // count - mult * buckets_[b], // percentage - mult * sum); // cumulative percentage - r.append(buf); - - // Add hash marks based on percentage; 20 marks for 100%. - int marks = static_cast(20*(buckets_[b] / num_) + 0.5); - r.append(marks, '#'); - r.push_back('\n'); - } - return r; -} - -} // namespace leveldb diff --git a/src/leveldb/util/histogram.h b/src/leveldb/util/histogram.h deleted file mode 100644 index 1ef9f3c8a..000000000 --- a/src/leveldb/util/histogram.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ -#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ - -#include - -namespace leveldb { - -class Histogram { - public: - Histogram() { } - ~Histogram() { } - - void Clear(); - void Add(double value); - void Merge(const Histogram& other); - - std::string ToString() const; - - private: - double min_; - double max_; - double num_; - double sum_; - double sum_squares_; - - enum { kNumBuckets = 154 }; - static const double kBucketLimit[kNumBuckets]; - double buckets_[kNumBuckets]; - - double Median() const; - double Percentile(double p) const; - double Average() const; - double StandardDeviation() const; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc deleted file mode 100644 index 22cf27851..000000000 --- a/src/leveldb/util/logging.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/logging.h" - -#include -#include -#include -#include -#include "leveldb/env.h" -#include "leveldb/slice.h" - -namespace leveldb { - -void AppendNumberTo(std::string* str, uint64_t num) { - char buf[30]; - snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num); - str->append(buf); -} - -void AppendEscapedStringTo(std::string* str, const Slice& value) { - for (size_t i = 0; i < value.size(); i++) { - char c = value[i]; - if (c >= ' ' && c <= '~') { - str->push_back(c); - } else { - char buf[10]; - snprintf(buf, sizeof(buf), "\\x%02x", - static_cast(c) & 0xff); - str->append(buf); - } - } -} - -std::string NumberToString(uint64_t num) { - std::string r; - AppendNumberTo(&r, num); - return r; -} - -std::string EscapeString(const Slice& value) { - std::string r; - AppendEscapedStringTo(&r, value); - return r; -} - -bool ConsumeChar(Slice* in, char c) { - if (!in->empty() && (*in)[0] == c) { - in->remove_prefix(1); - return true; - } else { - return false; - } -} - -bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { - uint64_t v = 0; - int digits = 0; - while (!in->empty()) { - char c = (*in)[0]; - if (c >= '0' && c <= '9') { - ++digits; - const int delta = (c - '0'); - static const uint64_t kMaxUint64 = ~static_cast(0); - if (v > kMaxUint64/10 || - (v == kMaxUint64/10 && delta > kMaxUint64%10)) { - // Overflow - return false; - } - v = (v * 10) + delta; - in->remove_prefix(1); - } else { - break; - } - } - *val = v; - return (digits > 0); -} - -} // namespace leveldb diff --git a/src/leveldb/util/logging.h b/src/leveldb/util/logging.h deleted file mode 100644 index b0c5da813..000000000 --- a/src/leveldb/util/logging.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Must not be included from any .h files to avoid polluting the namespace -// with macros. - -#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ -#define STORAGE_LEVELDB_UTIL_LOGGING_H_ - -#include -#include -#include -#include "port/port.h" - -namespace leveldb { - -class Slice; -class WritableFile; - -// Append a human-readable printout of "num" to *str -extern void AppendNumberTo(std::string* str, uint64_t num); - -// Append a human-readable printout of "value" to *str. -// Escapes any non-printable characters found in "value". -extern void AppendEscapedStringTo(std::string* str, const Slice& value); - -// Return a human-readable printout of "num" -extern std::string NumberToString(uint64_t num); - -// Return a human-readable version of "value". -// Escapes any non-printable characters found in "value". -extern std::string EscapeString(const Slice& value); - -// If *in starts with "c", advances *in past the first character and -// returns true. Otherwise, returns false. -extern bool ConsumeChar(Slice* in, char c); - -// Parse a human-readable number from "*in" into *value. On success, -// advances "*in" past the consumed number and sets "*val" to the -// numeric value. Otherwise, returns false and leaves *in in an -// unspecified state. -extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/src/leveldb/util/mutexlock.h b/src/leveldb/util/mutexlock.h deleted file mode 100644 index 1ff5a9efa..000000000 --- a/src/leveldb/util/mutexlock.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ -#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ - -#include "port/port.h" -#include "port/thread_annotations.h" - -namespace leveldb { - -// Helper class that locks a mutex on construction and unlocks the mutex when -// the destructor of the MutexLock object is invoked. -// -// Typical usage: -// -// void MyClass::MyMethod() { -// MutexLock l(&mu_); // mu_ is an instance variable -// ... some complex code, possibly with multiple return paths ... -// } - -class SCOPED_LOCKABLE MutexLock { - public: - explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) - : mu_(mu) { - this->mu_->Lock(); - } - ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } - - private: - port::Mutex *const mu_; - // No copying allowed - MutexLock(const MutexLock&); - void operator=(const MutexLock&); -}; - -} // namespace leveldb - - -#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/src/leveldb/util/options.cc b/src/leveldb/util/options.cc deleted file mode 100644 index 76af5b930..000000000 --- a/src/leveldb/util/options.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/options.h" - -#include "leveldb/comparator.h" -#include "leveldb/env.h" - -namespace leveldb { - -Options::Options() - : comparator(BytewiseComparator()), - create_if_missing(false), - error_if_exists(false), - paranoid_checks(false), - env(Env::Default()), - info_log(NULL), - write_buffer_size(4<<20), - max_open_files(1000), - block_cache(NULL), - block_size(4096), - block_restart_interval(16), - compression(kSnappyCompression), - filter_policy(NULL) { -} - - -} // namespace leveldb diff --git a/src/leveldb/util/posix_logger.h b/src/leveldb/util/posix_logger.h deleted file mode 100644 index c063c2b7c..000000000 --- a/src/leveldb/util/posix_logger.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Logger implementation that can be shared by all environments -// where enough Posix functionality is available. - -#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ -#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ - -#include -#include -#include -#include -#include "leveldb/env.h" - -namespace leveldb { - -class PosixLogger : public Logger { - private: - FILE* file_; - uint64_t (*gettid_)(); // Return the thread id for the current thread - public: - PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } - virtual ~PosixLogger() { - fclose(file_); - } - virtual void Logv(const char* format, va_list ap) { - const uint64_t thread_id = (*gettid_)(); - - // We try twice: the first time with a fixed-size stack allocated buffer, - // and the second time with a much larger dynamically allocated buffer. - char buffer[500]; - for (int iter = 0; iter < 2; iter++) { - char* base; - int bufsize; - if (iter == 0) { - bufsize = sizeof(buffer); - base = buffer; - } else { - bufsize = 30000; - base = new char[bufsize]; - } - char* p = base; - char* limit = base + bufsize; - - struct timeval now_tv; - gettimeofday(&now_tv, NULL); - const time_t seconds = now_tv.tv_sec; - struct tm t; - localtime_r(&seconds, &t); - p += snprintf(p, limit - p, - "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", - t.tm_year + 1900, - t.tm_mon + 1, - t.tm_mday, - t.tm_hour, - t.tm_min, - t.tm_sec, - static_cast(now_tv.tv_usec), - static_cast(thread_id)); - - // Print the message - if (p < limit) { - va_list backup_ap; - va_copy(backup_ap, ap); - p += vsnprintf(p, limit - p, format, backup_ap); - va_end(backup_ap); - } - - // Truncate to available space if necessary - if (p >= limit) { - if (iter == 0) { - continue; // Try again with larger buffer - } else { - p = limit - 1; - } - } - - // Add newline if necessary - if (p == base || p[-1] != '\n') { - *p++ = '\n'; - } - - assert(p <= limit); - fwrite(base, 1, p - base, file_); - fflush(file_); - if (base != buffer) { - delete[] base; - } - break; - } - } -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/src/leveldb/util/random.h b/src/leveldb/util/random.h deleted file mode 100644 index 07538242e..000000000 --- a/src/leveldb/util/random.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ -#define STORAGE_LEVELDB_UTIL_RANDOM_H_ - -#include - -namespace leveldb { - -// A very simple random number generator. Not especially good at -// generating truly random bits, but good enough for our needs in this -// package. -class Random { - private: - uint32_t seed_; - public: - explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { } - uint32_t Next() { - static const uint32_t M = 2147483647L; // 2^31-1 - static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 - // We are computing - // seed_ = (seed_ * A) % M, where M = 2^31-1 - // - // seed_ must not be zero or M, or else all subsequent computed values - // will be zero or M respectively. For all other values, seed_ will end - // up cycling through every number in [1,M-1] - uint64_t product = seed_ * A; - - // Compute (product % M) using the fact that ((x << 31) % M) == x. - seed_ = static_cast((product >> 31) + (product & M)); - // The first reduction may overflow by 1 bit, so we may need to - // repeat. mod == M is not possible; using > allows the faster - // sign-bit-based test. - if (seed_ > M) { - seed_ -= M; - } - return seed_; - } - // Returns a uniformly distributed value in the range [0..n-1] - // REQUIRES: n > 0 - uint32_t Uniform(int n) { return Next() % n; } - - // Randomly returns true ~"1/n" of the time, and false otherwise. - // REQUIRES: n > 0 - bool OneIn(int n) { return (Next() % n) == 0; } - - // Skewed: pick "base" uniformly from range [0,max_log] and then - // return "base" random bits. The effect is to pick a number in the - // range [0,2^max_log-1] with exponential bias towards smaller numbers. - uint32_t Skewed(int max_log) { - return Uniform(1 << Uniform(max_log + 1)); - } -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/src/leveldb/util/status.cc b/src/leveldb/util/status.cc deleted file mode 100644 index a44f35b31..000000000 --- a/src/leveldb/util/status.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "port/port.h" -#include "leveldb/status.h" - -namespace leveldb { - -const char* Status::CopyState(const char* state) { - uint32_t size; - memcpy(&size, state, sizeof(size)); - char* result = new char[size + 5]; - memcpy(result, state, size + 5); - return result; -} - -Status::Status(Code code, const Slice& msg, const Slice& msg2) { - assert(code != kOk); - const uint32_t len1 = msg.size(); - const uint32_t len2 = msg2.size(); - const uint32_t size = len1 + (len2 ? (2 + len2) : 0); - char* result = new char[size + 5]; - memcpy(result, &size, sizeof(size)); - result[4] = static_cast(code); - memcpy(result + 5, msg.data(), len1); - if (len2) { - result[5 + len1] = ':'; - result[6 + len1] = ' '; - memcpy(result + 7 + len1, msg2.data(), len2); - } - state_ = result; -} - -std::string Status::ToString() const { - if (state_ == NULL) { - return "OK"; - } else { - char tmp[30]; - const char* type; - switch (code()) { - case kOk: - type = "OK"; - break; - case kNotFound: - type = "NotFound: "; - break; - case kCorruption: - type = "Corruption: "; - break; - case kNotSupported: - type = "Not implemented: "; - break; - case kInvalidArgument: - type = "Invalid argument: "; - break; - case kIOError: - type = "IO error: "; - break; - default: - snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", - static_cast(code())); - type = tmp; - break; - } - std::string result(type); - uint32_t length; - memcpy(&length, state_, sizeof(length)); - result.append(state_ + 5, length); - return result; - } -} - -} // namespace leveldb diff --git a/src/leveldb/util/testharness.cc b/src/leveldb/util/testharness.cc deleted file mode 100644 index eb1bdd554..000000000 --- a/src/leveldb/util/testharness.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/testharness.h" - -#include -#include -#include -#include - -namespace leveldb { -namespace test { - -namespace { -struct Test { - const char* base; - const char* name; - void (*func)(); -}; -std::vector* tests; -} - -bool RegisterTest(const char* base, const char* name, void (*func)()) { - if (tests == NULL) { - tests = new std::vector; - } - Test t; - t.base = base; - t.name = name; - t.func = func; - tests->push_back(t); - return true; -} - -int RunAllTests() { - const char* matcher = getenv("LEVELDB_TESTS"); - - int num = 0; - if (tests != NULL) { - for (int i = 0; i < tests->size(); i++) { - const Test& t = (*tests)[i]; - if (matcher != NULL) { - std::string name = t.base; - name.push_back('.'); - name.append(t.name); - if (strstr(name.c_str(), matcher) == NULL) { - continue; - } - } - fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); - (*t.func)(); - ++num; - } - } - fprintf(stderr, "==== PASSED %d tests\n", num); - return 0; -} - -std::string TmpDir() { - std::string dir; - Status s = Env::Default()->GetTestDirectory(&dir); - ASSERT_TRUE(s.ok()) << s.ToString(); - return dir; -} - -int RandomSeed() { - const char* env = getenv("TEST_RANDOM_SEED"); - int result = (env != NULL ? atoi(env) : 301); - if (result <= 0) { - result = 301; - } - return result; -} - -} // namespace test -} // namespace leveldb diff --git a/src/leveldb/util/testharness.h b/src/leveldb/util/testharness.h deleted file mode 100644 index da4fe68bb..000000000 --- a/src/leveldb/util/testharness.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ -#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ - -#include -#include -#include -#include "leveldb/env.h" -#include "leveldb/slice.h" -#include "util/random.h" - -namespace leveldb { -namespace test { - -// Run some of the tests registered by the TEST() macro. If the -// environment variable "LEVELDB_TESTS" is not set, runs all tests. -// Otherwise, runs only the tests whose name contains the value of -// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: -// TEST(Foo, Hello) { ... } -// TEST(Foo, World) { ... } -// LEVELDB_TESTS=Hello will run the first test -// LEVELDB_TESTS=o will run both tests -// LEVELDB_TESTS=Junk will run no tests -// -// Returns 0 if all tests pass. -// Dies or returns a non-zero value if some test fails. -extern int RunAllTests(); - -// Return the directory to use for temporary storage. -extern std::string TmpDir(); - -// Return a randomization seed for this run. Typically returns the -// same number on repeated invocations of this binary, but automated -// runs may be able to vary the seed. -extern int RandomSeed(); - -// An instance of Tester is allocated to hold temporary state during -// the execution of an assertion. -class Tester { - private: - bool ok_; - const char* fname_; - int line_; - std::stringstream ss_; - - public: - Tester(const char* f, int l) - : ok_(true), fname_(f), line_(l) { - } - - ~Tester() { - if (!ok_) { - fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); - exit(1); - } - } - - Tester& Is(bool b, const char* msg) { - if (!b) { - ss_ << " Assertion failure " << msg; - ok_ = false; - } - return *this; - } - - Tester& IsOk(const Status& s) { - if (!s.ok()) { - ss_ << " " << s.ToString(); - ok_ = false; - } - return *this; - } - -#define BINARY_OP(name,op) \ - template \ - Tester& name(const X& x, const Y& y) { \ - if (! (x op y)) { \ - ss_ << " failed: " << x << (" " #op " ") << y; \ - ok_ = false; \ - } \ - return *this; \ - } - - BINARY_OP(IsEq, ==) - BINARY_OP(IsNe, !=) - BINARY_OP(IsGe, >=) - BINARY_OP(IsGt, >) - BINARY_OP(IsLe, <=) - BINARY_OP(IsLt, <) -#undef BINARY_OP - - // Attach the specified value to the error message if an error has occurred - template - Tester& operator<<(const V& value) { - if (!ok_) { - ss_ << " " << value; - } - return *this; - } -}; - -#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) -#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) -#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) -#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) -#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) -#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) -#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) -#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) - -#define TCONCAT(a,b) TCONCAT1(a,b) -#define TCONCAT1(a,b) a##b - -#define TEST(base,name) \ -class TCONCAT(_Test_,name) : public base { \ - public: \ - void _Run(); \ - static void _RunIt() { \ - TCONCAT(_Test_,name) t; \ - t._Run(); \ - } \ -}; \ -bool TCONCAT(_Test_ignored_,name) = \ - ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \ -void TCONCAT(_Test_,name)::_Run() - -// Register the specified test. Typically not used directly, but -// invoked via the macro expansion of TEST. -extern bool RegisterTest(const char* base, const char* name, void (*func)()); - - -} // namespace test -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/src/leveldb/util/testutil.cc b/src/leveldb/util/testutil.cc deleted file mode 100644 index 538d09516..000000000 --- a/src/leveldb/util/testutil.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/testutil.h" - -#include "util/random.h" - -namespace leveldb { -namespace test { - -Slice RandomString(Random* rnd, int len, std::string* dst) { - dst->resize(len); - for (int i = 0; i < len; i++) { - (*dst)[i] = static_cast(' ' + rnd->Uniform(95)); // ' ' .. '~' - } - return Slice(*dst); -} - -std::string RandomKey(Random* rnd, int len) { - // Make sure to generate a wide variety of characters so we - // test the boundary conditions for short-key optimizations. - static const char kTestChars[] = { - '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' - }; - std::string result; - for (int i = 0; i < len; i++) { - result += kTestChars[rnd->Uniform(sizeof(kTestChars))]; - } - return result; -} - - -extern Slice CompressibleString(Random* rnd, double compressed_fraction, - int len, std::string* dst) { - int raw = static_cast(len * compressed_fraction); - if (raw < 1) raw = 1; - std::string raw_data; - RandomString(rnd, raw, &raw_data); - - // Duplicate the random data until we have filled "len" bytes - dst->clear(); - while (dst->size() < len) { - dst->append(raw_data); - } - dst->resize(len); - return Slice(*dst); -} - -} // namespace test -} // namespace leveldb diff --git a/src/leveldb/util/testutil.h b/src/leveldb/util/testutil.h deleted file mode 100644 index 824e655bd..000000000 --- a/src/leveldb/util/testutil.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ -#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ - -#include "leveldb/env.h" -#include "leveldb/slice.h" -#include "util/random.h" - -namespace leveldb { -namespace test { - -// Store in *dst a random string of length "len" and return a Slice that -// references the generated data. -extern Slice RandomString(Random* rnd, int len, std::string* dst); - -// Return a random key with the specified length that may contain interesting -// characters (e.g. \x00, \xff, etc.). -extern std::string RandomKey(Random* rnd, int len); - -// Store in *dst a string of length "len" that will compress to -// "N*compressed_fraction" bytes and return a Slice that references -// the generated data. -extern Slice CompressibleString(Random* rnd, double compressed_fraction, - int len, std::string* dst); - -// A wrapper that allows injection of errors. -class ErrorEnv : public EnvWrapper { - public: - bool writable_file_error_; - int num_writable_file_errors_; - - ErrorEnv() : EnvWrapper(Env::Default()), - writable_file_error_(false), - num_writable_file_errors_(0) { } - - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) { - if (writable_file_error_) { - ++num_writable_file_errors_; - *result = NULL; - return Status::IOError(fname, "fake error"); - } - return target()->NewWritableFile(fname, result); - } -}; - -} // namespace test -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ From c25e98186d0f716451ef000e55646d25e014f573 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 3 May 2013 19:06:59 -0700 Subject: [PATCH 25/69] Squashed 'src/leveldb/' content from commit aca1ffc git-subtree-dir: src/leveldb git-subtree-split: aca1ffc4b65be5e099b2088c6e6a308d69e1ad73 --- .gitignore | 12 + AUTHORS | 8 + LICENSE | 27 + Makefile | 202 +++ NEWS | 17 + README | 51 + TODO | 14 + WINDOWS.md | 39 + build_detect_platform | 200 +++ db/builder.cc | 88 ++ db/builder.h | 34 + db/c.cc | 595 +++++++++ db/c_test.c | 390 ++++++ db/corruption_test.cc | 359 ++++++ db/db_bench.cc | 979 +++++++++++++++ db/db_impl.cc | 1467 ++++++++++++++++++++++ db/db_impl.h | 202 +++ db/db_iter.cc | 299 +++++ db/db_iter.h | 26 + db/db_test.cc | 2027 +++++++++++++++++++++++++++++++ db/dbformat.cc | 140 +++ db/dbformat.h | 227 ++++ db/dbformat_test.cc | 112 ++ db/filename.cc | 139 +++ db/filename.h | 80 ++ db/filename_test.cc | 122 ++ db/leveldb_main.cc | 238 ++++ db/log_format.h | 35 + db/log_reader.cc | 259 ++++ db/log_reader.h | 108 ++ db/log_test.cc | 500 ++++++++ db/log_writer.cc | 103 ++ db/log_writer.h | 48 + db/memtable.cc | 145 +++ db/memtable.h | 91 ++ db/repair.cc | 389 ++++++ db/skiplist.h | 379 ++++++ db/skiplist_test.cc | 378 ++++++ db/snapshot.h | 66 + db/table_cache.cc | 121 ++ db/table_cache.h | 61 + db/version_edit.cc | 266 ++++ db/version_edit.h | 107 ++ db/version_edit_test.cc | 46 + db/version_set.cc | 1438 ++++++++++++++++++++++ db/version_set.h | 383 ++++++ db/version_set_test.cc | 179 +++ db/write_batch.cc | 147 +++ db/write_batch_internal.h | 49 + db/write_batch_test.cc | 120 ++ doc/bench/db_bench_sqlite3.cc | 718 +++++++++++ doc/bench/db_bench_tree_db.cc | 528 ++++++++ doc/benchmark.html | 459 +++++++ doc/doc.css | 89 ++ doc/impl.html | 213 ++++ doc/index.html | 549 +++++++++ doc/log_format.txt | 75 ++ doc/table_format.txt | 104 ++ helpers/memenv/memenv.cc | 384 ++++++ helpers/memenv/memenv.h | 20 + helpers/memenv/memenv_test.cc | 232 ++++ include/leveldb/c.h | 291 +++++ include/leveldb/cache.h | 99 ++ include/leveldb/comparator.h | 63 + include/leveldb/db.h | 161 +++ include/leveldb/env.h | 333 +++++ include/leveldb/filter_policy.h | 70 ++ include/leveldb/iterator.h | 100 ++ include/leveldb/options.h | 195 +++ include/leveldb/slice.h | 109 ++ include/leveldb/status.h | 106 ++ include/leveldb/table.h | 85 ++ include/leveldb/table_builder.h | 92 ++ include/leveldb/write_batch.h | 64 + port/README | 10 + port/atomic_pointer.h | 224 ++++ port/port.h | 21 + port/port_example.h | 135 ++ port/port_posix.cc | 54 + port/port_posix.h | 157 +++ port/port_win.cc | 149 +++ port/port_win.h | 174 +++ port/thread_annotations.h | 59 + port/win/stdint.h | 24 + table/block.cc | 267 ++++ table/block.h | 44 + table/block_builder.cc | 109 ++ table/block_builder.h | 57 + table/filter_block.cc | 111 ++ table/filter_block.h | 68 ++ table/filter_block_test.cc | 128 ++ table/format.cc | 145 +++ table/format.h | 108 ++ table/iterator.cc | 67 + table/iterator_wrapper.h | 63 + table/merger.cc | 197 +++ table/merger.h | 26 + table/table.cc | 276 +++++ table/table_builder.cc | 270 ++++ table/table_test.cc | 838 +++++++++++++ table/two_level_iterator.cc | 182 +++ table/two_level_iterator.h | 34 + util/arena.cc | 68 ++ util/arena.h | 68 ++ util/arena_test.cc | 68 ++ util/bloom.cc | 95 ++ util/bloom_test.cc | 160 +++ util/cache.cc | 328 +++++ util/cache_test.cc | 186 +++ util/coding.cc | 194 +++ util/coding.h | 104 ++ util/coding_test.cc | 196 +++ util/comparator.cc | 81 ++ util/crc32c.cc | 332 +++++ util/crc32c.h | 45 + util/crc32c_test.cc | 72 ++ util/env.cc | 96 ++ util/env_posix.cc | 701 +++++++++++ util/env_test.cc | 104 ++ util/env_win.cc | 1031 ++++++++++++++++ util/filter_policy.cc | 11 + util/hash.cc | 45 + util/hash.h | 19 + util/histogram.cc | 139 +++ util/histogram.h | 42 + util/logging.cc | 81 ++ util/logging.h | 47 + util/mutexlock.h | 41 + util/options.cc | 29 + util/posix_logger.h | 98 ++ util/random.h | 59 + util/status.cc | 75 ++ util/testharness.cc | 77 ++ util/testharness.h | 138 +++ util/testutil.cc | 51 + util/testutil.h | 53 + 136 files changed, 27582 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100644 WINDOWS.md create mode 100755 build_detect_platform create mode 100644 db/builder.cc create mode 100644 db/builder.h create mode 100644 db/c.cc create mode 100644 db/c_test.c create mode 100644 db/corruption_test.cc create mode 100644 db/db_bench.cc create mode 100644 db/db_impl.cc create mode 100644 db/db_impl.h create mode 100644 db/db_iter.cc create mode 100644 db/db_iter.h create mode 100644 db/db_test.cc create mode 100644 db/dbformat.cc create mode 100644 db/dbformat.h create mode 100644 db/dbformat_test.cc create mode 100644 db/filename.cc create mode 100644 db/filename.h create mode 100644 db/filename_test.cc create mode 100644 db/leveldb_main.cc create mode 100644 db/log_format.h create mode 100644 db/log_reader.cc create mode 100644 db/log_reader.h create mode 100644 db/log_test.cc create mode 100644 db/log_writer.cc create mode 100644 db/log_writer.h create mode 100644 db/memtable.cc create mode 100644 db/memtable.h create mode 100644 db/repair.cc create mode 100644 db/skiplist.h create mode 100644 db/skiplist_test.cc create mode 100644 db/snapshot.h create mode 100644 db/table_cache.cc create mode 100644 db/table_cache.h create mode 100644 db/version_edit.cc create mode 100644 db/version_edit.h create mode 100644 db/version_edit_test.cc create mode 100644 db/version_set.cc create mode 100644 db/version_set.h create mode 100644 db/version_set_test.cc create mode 100644 db/write_batch.cc create mode 100644 db/write_batch_internal.h create mode 100644 db/write_batch_test.cc create mode 100644 doc/bench/db_bench_sqlite3.cc create mode 100644 doc/bench/db_bench_tree_db.cc create mode 100644 doc/benchmark.html create mode 100644 doc/doc.css create mode 100644 doc/impl.html create mode 100644 doc/index.html create mode 100644 doc/log_format.txt create mode 100644 doc/table_format.txt create mode 100644 helpers/memenv/memenv.cc create mode 100644 helpers/memenv/memenv.h create mode 100644 helpers/memenv/memenv_test.cc create mode 100644 include/leveldb/c.h create mode 100644 include/leveldb/cache.h create mode 100644 include/leveldb/comparator.h create mode 100644 include/leveldb/db.h create mode 100644 include/leveldb/env.h create mode 100644 include/leveldb/filter_policy.h create mode 100644 include/leveldb/iterator.h create mode 100644 include/leveldb/options.h create mode 100644 include/leveldb/slice.h create mode 100644 include/leveldb/status.h create mode 100644 include/leveldb/table.h create mode 100644 include/leveldb/table_builder.h create mode 100644 include/leveldb/write_batch.h create mode 100644 port/README create mode 100644 port/atomic_pointer.h create mode 100644 port/port.h create mode 100644 port/port_example.h create mode 100644 port/port_posix.cc create mode 100644 port/port_posix.h create mode 100644 port/port_win.cc create mode 100644 port/port_win.h create mode 100644 port/thread_annotations.h create mode 100644 port/win/stdint.h create mode 100644 table/block.cc create mode 100644 table/block.h create mode 100644 table/block_builder.cc create mode 100644 table/block_builder.h create mode 100644 table/filter_block.cc create mode 100644 table/filter_block.h create mode 100644 table/filter_block_test.cc create mode 100644 table/format.cc create mode 100644 table/format.h create mode 100644 table/iterator.cc create mode 100644 table/iterator_wrapper.h create mode 100644 table/merger.cc create mode 100644 table/merger.h create mode 100644 table/table.cc create mode 100644 table/table_builder.cc create mode 100644 table/table_test.cc create mode 100644 table/two_level_iterator.cc create mode 100644 table/two_level_iterator.h create mode 100644 util/arena.cc create mode 100644 util/arena.h create mode 100644 util/arena_test.cc create mode 100644 util/bloom.cc create mode 100644 util/bloom_test.cc create mode 100644 util/cache.cc create mode 100644 util/cache_test.cc create mode 100644 util/coding.cc create mode 100644 util/coding.h create mode 100644 util/coding_test.cc create mode 100644 util/comparator.cc create mode 100644 util/crc32c.cc create mode 100644 util/crc32c.h create mode 100644 util/crc32c_test.cc create mode 100644 util/env.cc create mode 100644 util/env_posix.cc create mode 100644 util/env_test.cc create mode 100644 util/env_win.cc create mode 100644 util/filter_policy.cc create mode 100644 util/hash.cc create mode 100644 util/hash.h create mode 100644 util/histogram.cc create mode 100644 util/histogram.h create mode 100644 util/logging.cc create mode 100644 util/logging.h create mode 100644 util/mutexlock.h create mode 100644 util/options.cc create mode 100644 util/posix_logger.h create mode 100644 util/random.h create mode 100644 util/status.cc create mode 100644 util/testharness.cc create mode 100644 util/testharness.h create mode 100644 util/testutil.cc create mode 100644 util/testutil.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..55ba072e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +build_config.mk +*.a +*.o +*.dylib* +*.so +*.so.* +*_test +db_bench +Release +Debug +Benchmark +vs2010.* diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..27a9407e5 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +# Names should be added to this file like so: +# Name or Organization + +Google Inc. + +# Initial version authors: +Jeffrey Dean +Sanjay Ghemawat diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..8e80208cd --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..42c4952fe --- /dev/null +++ b/Makefile @@ -0,0 +1,202 @@ +# Copyright (c) 2011 The LevelDB Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. See the AUTHORS file for names of contributors. + +#----------------------------------------------- +# Uncomment exactly one of the lines labelled (A), (B), and (C) below +# to switch between compilation modes. + +OPT ?= -O2 -DNDEBUG # (A) Production use (optimized mode) +# OPT ?= -g2 # (B) Debug mode, w/ full line-level debugging symbols +# OPT ?= -O2 -g2 -DNDEBUG # (C) Profiling mode: opt, but w/debugging symbols +#----------------------------------------------- + +# detect what platform we're building on +$(shell CC=$(CC) CXX=$(CXX) TARGET_OS=$(TARGET_OS) \ + ./build_detect_platform build_config.mk ./) +# this file is generated by the previous line to set build flags and sources +include build_config.mk + +CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) +CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) + +LDFLAGS += $(PLATFORM_LDFLAGS) +LIBS += $(PLATFORM_LIBS) + +LIBOBJECTS = $(SOURCES:.cc=.o) +MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o) + +TESTUTIL = ./util/testutil.o +TESTHARNESS = ./util/testharness.o $(TESTUTIL) + +TESTS = \ + arena_test \ + bloom_test \ + c_test \ + cache_test \ + coding_test \ + corruption_test \ + crc32c_test \ + db_test \ + dbformat_test \ + env_test \ + filename_test \ + filter_block_test \ + log_test \ + memenv_test \ + skiplist_test \ + table_test \ + version_edit_test \ + version_set_test \ + write_batch_test + +PROGRAMS = db_bench leveldbutil $(TESTS) +BENCHMARKS = db_bench_sqlite3 db_bench_tree_db + +LIBRARY = libleveldb.a +MEMENVLIBRARY = libmemenv.a + +default: all + +# Should we build shared libraries? +ifneq ($(PLATFORM_SHARED_EXT),) + +ifneq ($(PLATFORM_SHARED_VERSIONED),true) +SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) +SHARED2 = $(SHARED1) +SHARED3 = $(SHARED1) +SHARED = $(SHARED1) +else +# Update db.h if you change these. +SHARED_MAJOR = 1 +SHARED_MINOR = 9 +SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) +SHARED2 = $(SHARED1).$(SHARED_MAJOR) +SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) +SHARED = $(SHARED1) $(SHARED2) $(SHARED3) +$(SHARED1): $(SHARED3) + ln -fs $(SHARED3) $(SHARED1) +$(SHARED2): $(SHARED3) + ln -fs $(SHARED3) $(SHARED2) +endif + +$(SHARED3): + $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) $(LIBS) + +endif # PLATFORM_SHARED_EXT + +all: $(SHARED) $(LIBRARY) + +check: all $(PROGRAMS) $(TESTS) + for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done + +clean: + -rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) */*.o */*/*.o ios-x86/*/*.o ios-arm/*/*.o build_config.mk + -rm -rf ios-x86/* ios-arm/* + +$(LIBRARY): $(LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(LIBOBJECTS) + +db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) + +db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS) + +db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS) + +leveldbutil: db/leveldb_main.o $(LIBOBJECTS) + $(CXX) $(LDFLAGS) db/leveldb_main.o $(LIBOBJECTS) -o $@ $(LIBS) + +arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(MEMENVLIBRARY) : $(MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(MEMENVOBJECTS) + +memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) + $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS) + +ifeq ($(PLATFORM), IOS) +# For iOS, create universal object files to be used on both the simulator and +# a device. +PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms +SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer +DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer +IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString) + +.cc.o: + mkdir -p ios-x86/$(dir $@) + $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ + mkdir -p ios-arm/$(dir $@) + $(DEVICEROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ + lipo ios-x86/$@ ios-arm/$@ -create -output $@ + +.c.o: + mkdir -p ios-x86/$(dir $@) + $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ + mkdir -p ios-arm/$(dir $@) + $(DEVICEROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ + lipo ios-x86/$@ ios-arm/$@ -create -output $@ + +else +.cc.o: + $(CXX) $(CXXFLAGS) -c $< -o $@ + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ +endif diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..3fd99242d --- /dev/null +++ b/NEWS @@ -0,0 +1,17 @@ +Release 1.2 2011-05-16 +---------------------- + +Fixes for larger databases (tested up to one billion 100-byte entries, +i.e., ~100GB). + +(1) Place hard limit on number of level-0 files. This fixes errors +of the form "too many open files". + +(2) Fixed memtable management. Before the fix, a heavy write burst +could cause unbounded memory usage. + +A fix for a logging bug where the reader would incorrectly complain +about corruption. + +Allow public access to WriteBatch contents so that users can easily +wrap a DB. diff --git a/README b/README new file mode 100644 index 000000000..3618adeee --- /dev/null +++ b/README @@ -0,0 +1,51 @@ +leveldb: A key-value store +Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) + +The code under this directory implements a system for maintaining a +persistent key/value store. + +See doc/index.html for more explanation. +See doc/impl.html for a brief overview of the implementation. + +The public interface is in include/*.h. Callers should not include or +rely on the details of any other header files in this package. Those +internal APIs may be changed without warning. + +Guide to header files: + +include/db.h + Main interface to the DB: Start here + +include/options.h + Control over the behavior of an entire database, and also + control over the behavior of individual reads and writes. + +include/comparator.h + Abstraction for user-specified comparison function. If you want + just bytewise comparison of keys, you can use the default comparator, + but clients can write their own comparator implementations if they + want custom ordering (e.g. to handle different character + encodings, etc.) + +include/iterator.h + Interface for iterating over data. You can get an iterator + from a DB object. + +include/write_batch.h + Interface for atomically applying multiple updates to a database. + +include/slice.h + A simple module for maintaining a pointer and a length into some + other byte array. + +include/status.h + Status is returned from many of the public interfaces and is used + to report success and various kinds of errors. + +include/env.h + Abstraction of the OS environment. A posix implementation of + this interface is in util/env_posix.cc + +include/table.h +include/table_builder.h + Lower-level modules that most clients probably won't use directly diff --git a/TODO b/TODO new file mode 100644 index 000000000..e603c0713 --- /dev/null +++ b/TODO @@ -0,0 +1,14 @@ +ss +- Stats + +db +- Maybe implement DB::BulkDeleteForRange(start_key, end_key) + that would blow away files whose ranges are entirely contained + within [start_key..end_key]? For Chrome, deletion of obsolete + object stores, etc. can be done in the background anyway, so + probably not that important. +- There have been requests for MultiGet. + +After a range is completely deleted, what gets rid of the +corresponding files if we do no future changes to that range. Make +the conditions for triggering compactions fire in more situations? diff --git a/WINDOWS.md b/WINDOWS.md new file mode 100644 index 000000000..5b76c2448 --- /dev/null +++ b/WINDOWS.md @@ -0,0 +1,39 @@ +# Building LevelDB On Windows + +## Prereqs + +Install the [Windows Software Development Kit version 7.1](http://www.microsoft.com/downloads/dlx/en-us/listdetailsview.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b). + +Download and extract the [Snappy source distribution](http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz) + +1. Open the "Windows SDK 7.1 Command Prompt" : + Start Menu -> "Microsoft Windows SDK v7.1" > "Windows SDK 7.1 Command Prompt" +2. Change the directory to the leveldb project + +## Building the Static lib + +* 32 bit Version + + setenv /x86 + msbuild.exe /p:Configuration=Release /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 + +* 64 bit Version + + setenv /x64 + msbuild.exe /p:Configuration=Release /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 + + +## Building and Running the Benchmark app + +* 32 bit Version + + setenv /x86 + msbuild.exe /p:Configuration=Benchmark /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 + Benchmark\leveldb.exe + +* 64 bit Version + + setenv /x64 + msbuild.exe /p:Configuration=Benchmark /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 + x64\Benchmark\leveldb.exe + diff --git a/build_detect_platform b/build_detect_platform new file mode 100755 index 000000000..609cb5122 --- /dev/null +++ b/build_detect_platform @@ -0,0 +1,200 @@ +#!/bin/sh +# +# Detects OS we're compiling on and outputs a file specified by the first +# argument, which in turn gets read while processing Makefile. +# +# The output will set the following variables: +# CC C Compiler path +# CXX C++ Compiler path +# PLATFORM_LDFLAGS Linker flags +# PLATFORM_LIBS Libraries flags +# PLATFORM_SHARED_EXT Extension for shared libraries +# PLATFORM_SHARED_LDFLAGS Flags for building shared library +# This flag is embedded just before the name +# of the shared library without intervening spaces +# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library +# PLATFORM_CCFLAGS C compiler flags +# PLATFORM_CXXFLAGS C++ compiler flags. Will contain: +# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned +# shared libraries, empty otherwise. +# +# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following: +# +# -DLEVELDB_CSTDATOMIC_PRESENT if is present +# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms +# -DSNAPPY if the Snappy library is present +# + +OUTPUT=$1 +PREFIX=$2 +if test -z "$OUTPUT" || test -z "$PREFIX"; then + echo "usage: $0 " >&2 + exit 1 +fi + +# Delete existing output, if it exists +rm -f $OUTPUT +touch $OUTPUT + +if test -z "$CC"; then + CC=cc +fi + +if test -z "$CXX"; then + CXX=g++ +fi + +# Detect OS +if test -z "$TARGET_OS"; then + TARGET_OS=`uname -s` +fi + +COMMON_FLAGS= +CROSS_COMPILE= +PLATFORM_CCFLAGS= +PLATFORM_CXXFLAGS= +PLATFORM_LDFLAGS= +PLATFORM_LIBS= +PLATFORM_SHARED_EXT="so" +PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," +PLATFORM_SHARED_CFLAGS="-fPIC" +PLATFORM_SHARED_VERSIONED=true + +MEMCMP_FLAG= +if [ "$CXX" = "g++" ]; then + # Use libc's memcmp instead of GCC's memcmp. This results in ~40% + # performance improvement on readrandom under gcc 4.4.3 on Linux/x86. + MEMCMP_FLAG="-fno-builtin-memcmp" +fi + +case "$TARGET_OS" in + Darwin) + PLATFORM=OS_MACOSX + COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" + PLATFORM_SHARED_EXT=dylib + [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` + PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/" + PORT_FILE=port/port_posix.cc + ;; + Linux) + PLATFORM=OS_LINUX + COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + ;; + SunOS) + PLATFORM=OS_SOLARIS + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS" + PLATFORM_LIBS="-lpthread -lrt" + PORT_FILE=port/port_posix.cc + ;; + FreeBSD) + PLATFORM=OS_FREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; + NetBSD) + PLATFORM=OS_NETBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" + PLATFORM_LIBS="-lpthread -lgcc_s" + PORT_FILE=port/port_posix.cc + ;; + OpenBSD) + PLATFORM=OS_OPENBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + ;; + DragonFly) + PLATFORM=OS_DRAGONFLYBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; + OS_ANDROID_CROSSCOMPILE) + PLATFORM=OS_ANDROID + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" + PLATFORM_LDFLAGS="" # All pthread features are in the Android C library + PORT_FILE=port/port_posix.cc + CROSS_COMPILE=true + ;; + HP-UX) + PLATFORM=OS_HPUX + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + # man ld: +h internal_name + PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl," + ;; + OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) + PLATFORM=OS_WINDOWS + COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1" + PLATFORM_SOURCES="util/env_win.cc" + PLATFORM_LIBS="-lshlwapi" + PORT_FILE=port/port_win.cc + CROSS_COMPILE=true + ;; + *) + echo "Unknown platform!" >&2 + exit 1 +esac + +# We want to make a list of all cc files within util, db, table, and helpers +# except for the test and benchmark files. By default, find will output a list +# of all files matching either rule, so we need to append -print to make the +# prune take effect. +DIRS="$PREFIX/db $PREFIX/util $PREFIX/table" + +set -f # temporarily disable globbing so that our patterns aren't expanded +PRUNE_TEST="-name *test*.cc -prune" +PRUNE_BENCH="-name *_bench.cc -prune" +PRUNE_TOOL="-name leveldb_main.cc -prune" +PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "` + +set +f # re-enable globbing + +# The sources consist of the portable files, plus the platform-specific port +# file. +echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT +echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT + +if [ "$CROSS_COMPILE" = "true" ]; then + # Cross-compiling; do not try any compilation tests. + true +else + # If -std=c++0x works, use . Otherwise use port_posix.h. + $CXX $CXXFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null < + int main() {} +EOF + if [ "$?" = 0 ]; then + COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_CSTDATOMIC_PRESENT" + PLATFORM_CXXFLAGS="-std=c++0x" + else + COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX" + fi + + # Test whether tcmalloc is available + $CXX $CXXFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null <> $OUTPUT +echo "CXX=$CXX" >> $OUTPUT +echo "PLATFORM=$PLATFORM" >> $OUTPUT +echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT +echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT +echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT +echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT +echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT diff --git a/db/builder.cc b/db/builder.cc new file mode 100644 index 000000000..f41988219 --- /dev/null +++ b/db/builder.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/builder.h" + +#include "db/filename.h" +#include "db/dbformat.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" + +namespace leveldb { + +Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta) { + Status s; + meta->file_size = 0; + iter->SeekToFirst(); + + std::string fname = TableFileName(dbname, meta->number); + if (iter->Valid()) { + WritableFile* file; + s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + + TableBuilder* builder = new TableBuilder(options, file); + meta->smallest.DecodeFrom(iter->key()); + for (; iter->Valid(); iter->Next()) { + Slice key = iter->key(); + meta->largest.DecodeFrom(key); + builder->Add(key, iter->value()); + } + + // Finish and check for builder errors + if (s.ok()) { + s = builder->Finish(); + if (s.ok()) { + meta->file_size = builder->FileSize(); + assert(meta->file_size > 0); + } + } else { + builder->Abandon(); + } + delete builder; + + // Finish and check for file errors + if (s.ok()) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; + file = NULL; + + if (s.ok()) { + // Verify that the table is usable + Iterator* it = table_cache->NewIterator(ReadOptions(), + meta->number, + meta->file_size); + s = it->status(); + delete it; + } + } + + // Check for input iterator errors + if (!iter->status().ok()) { + s = iter->status(); + } + + if (s.ok() && meta->file_size > 0) { + // Keep it + } else { + env->DeleteFile(fname); + } + return s; +} + +} // namespace leveldb diff --git a/db/builder.h b/db/builder.h new file mode 100644 index 000000000..62431fcf4 --- /dev/null +++ b/db/builder.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ +#define STORAGE_LEVELDB_DB_BUILDER_H_ + +#include "leveldb/status.h" + +namespace leveldb { + +struct Options; +struct FileMetaData; + +class Env; +class Iterator; +class TableCache; +class VersionEdit; + +// Build a Table file from the contents of *iter. The generated file +// will be named according to meta->number. On success, the rest of +// *meta will be filled with metadata about the generated table. +// If no data is present in *iter, meta->file_size will be set to +// zero, and no Table file will be produced. +extern Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/db/c.cc b/db/c.cc new file mode 100644 index 000000000..08ff0ad90 --- /dev/null +++ b/db/c.cc @@ -0,0 +1,595 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/c.h" + +#include +#include +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/write_batch.h" + +using leveldb::Cache; +using leveldb::Comparator; +using leveldb::CompressionType; +using leveldb::DB; +using leveldb::Env; +using leveldb::FileLock; +using leveldb::FilterPolicy; +using leveldb::Iterator; +using leveldb::kMajorVersion; +using leveldb::kMinorVersion; +using leveldb::Logger; +using leveldb::NewBloomFilterPolicy; +using leveldb::NewLRUCache; +using leveldb::Options; +using leveldb::RandomAccessFile; +using leveldb::Range; +using leveldb::ReadOptions; +using leveldb::SequentialFile; +using leveldb::Slice; +using leveldb::Snapshot; +using leveldb::Status; +using leveldb::WritableFile; +using leveldb::WriteBatch; +using leveldb::WriteOptions; + +extern "C" { + +struct leveldb_t { DB* rep; }; +struct leveldb_iterator_t { Iterator* rep; }; +struct leveldb_writebatch_t { WriteBatch rep; }; +struct leveldb_snapshot_t { const Snapshot* rep; }; +struct leveldb_readoptions_t { ReadOptions rep; }; +struct leveldb_writeoptions_t { WriteOptions rep; }; +struct leveldb_options_t { Options rep; }; +struct leveldb_cache_t { Cache* rep; }; +struct leveldb_seqfile_t { SequentialFile* rep; }; +struct leveldb_randomfile_t { RandomAccessFile* rep; }; +struct leveldb_writablefile_t { WritableFile* rep; }; +struct leveldb_logger_t { Logger* rep; }; +struct leveldb_filelock_t { FileLock* rep; }; + +struct leveldb_comparator_t : public Comparator { + void* state_; + void (*destructor_)(void*); + int (*compare_)( + void*, + const char* a, size_t alen, + const char* b, size_t blen); + const char* (*name_)(void*); + + virtual ~leveldb_comparator_t() { + (*destructor_)(state_); + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + // No-ops since the C binding does not support key shortening methods. + virtual void FindShortestSeparator(std::string*, const Slice&) const { } + virtual void FindShortSuccessor(std::string* key) const { } +}; + +struct leveldb_filterpolicy_t : public FilterPolicy { + void* state_; + void (*destructor_)(void*); + const char* (*name_)(void*); + char* (*create_)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length); + unsigned char (*key_match_)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length); + + virtual ~leveldb_filterpolicy_t() { + (*destructor_)(state_); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + std::vector key_pointers(n); + std::vector key_sizes(n); + for (int i = 0; i < n; i++) { + key_pointers[i] = keys[i].data(); + key_sizes[i] = keys[i].size(); + } + size_t len; + char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); + dst->append(filter, len); + free(filter); + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return (*key_match_)(state_, key.data(), key.size(), + filter.data(), filter.size()); + } +}; + +struct leveldb_env_t { + Env* rep; + bool is_default; +}; + +static bool SaveError(char** errptr, const Status& s) { + assert(errptr != NULL); + if (s.ok()) { + return false; + } else if (*errptr == NULL) { + *errptr = strdup(s.ToString().c_str()); + } else { + // TODO(sanjay): Merge with existing error? + free(*errptr); + *errptr = strdup(s.ToString().c_str()); + } + return true; +} + +static char* CopyString(const std::string& str) { + char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); + memcpy(result, str.data(), sizeof(char) * str.size()); + return result; +} + +leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr) { + DB* db; + if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { + return NULL; + } + leveldb_t* result = new leveldb_t; + result->rep = db; + return result; +} + +void leveldb_close(leveldb_t* db) { + delete db->rep; + delete db; +} + +void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr) { + SaveError(errptr, + db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); +} + +void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr) { + SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); +} + + +void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr) { + SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); +} + +char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr) { + char* result = NULL; + std::string tmp; + Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); + if (s.ok()) { + *vallen = tmp.size(); + result = CopyString(tmp); + } else { + *vallen = 0; + if (!s.IsNotFound()) { + SaveError(errptr, s); + } + } + return result; +} + +leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options) { + leveldb_iterator_t* result = new leveldb_iterator_t; + result->rep = db->rep->NewIterator(options->rep); + return result; +} + +const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db) { + leveldb_snapshot_t* result = new leveldb_snapshot_t; + result->rep = db->rep->GetSnapshot(); + return result; +} + +void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot) { + db->rep->ReleaseSnapshot(snapshot->rep); + delete snapshot; +} + +char* leveldb_property_value( + leveldb_t* db, + const char* propname) { + std::string tmp; + if (db->rep->GetProperty(Slice(propname), &tmp)) { + // We use strdup() since we expect human readable output. + return strdup(tmp.c_str()); + } else { + return NULL; + } +} + +void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes) { + Range* ranges = new Range[num_ranges]; + for (int i = 0; i < num_ranges; i++) { + ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); + ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); + } + db->rep->GetApproximateSizes(ranges, num_ranges, sizes); + delete[] ranges; +} + +void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len) { + Slice a, b; + db->rep->CompactRange( + // Pass NULL Slice if corresponding "const char*" is NULL + (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), + (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); +} + +void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, DestroyDB(name, options->rep)); +} + +void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, RepairDB(name, options->rep)); +} + +void leveldb_iter_destroy(leveldb_iterator_t* iter) { + delete iter->rep; + delete iter; +} + +unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { + return iter->rep->Valid(); +} + +void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { + iter->rep->SeekToFirst(); +} + +void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { + iter->rep->SeekToLast(); +} + +void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { + iter->rep->Seek(Slice(k, klen)); +} + +void leveldb_iter_next(leveldb_iterator_t* iter) { + iter->rep->Next(); +} + +void leveldb_iter_prev(leveldb_iterator_t* iter) { + iter->rep->Prev(); +} + +const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { + Slice s = iter->rep->key(); + *klen = s.size(); + return s.data(); +} + +const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { + Slice s = iter->rep->value(); + *vlen = s.size(); + return s.data(); +} + +void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { + SaveError(errptr, iter->rep->status()); +} + +leveldb_writebatch_t* leveldb_writebatch_create() { + return new leveldb_writebatch_t; +} + +void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { + delete b; +} + +void leveldb_writebatch_clear(leveldb_writebatch_t* b) { + b->rep.Clear(); +} + +void leveldb_writebatch_put( + leveldb_writebatch_t* b, + const char* key, size_t klen, + const char* val, size_t vlen) { + b->rep.Put(Slice(key, klen), Slice(val, vlen)); +} + +void leveldb_writebatch_delete( + leveldb_writebatch_t* b, + const char* key, size_t klen) { + b->rep.Delete(Slice(key, klen)); +} + +void leveldb_writebatch_iterate( + leveldb_writebatch_t* b, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)) { + class H : public WriteBatch::Handler { + public: + void* state_; + void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); + void (*deleted_)(void*, const char* k, size_t klen); + virtual void Put(const Slice& key, const Slice& value) { + (*put_)(state_, key.data(), key.size(), value.data(), value.size()); + } + virtual void Delete(const Slice& key) { + (*deleted_)(state_, key.data(), key.size()); + } + }; + H handler; + handler.state_ = state; + handler.put_ = put; + handler.deleted_ = deleted; + b->rep.Iterate(&handler); +} + +leveldb_options_t* leveldb_options_create() { + return new leveldb_options_t; +} + +void leveldb_options_destroy(leveldb_options_t* options) { + delete options; +} + +void leveldb_options_set_comparator( + leveldb_options_t* opt, + leveldb_comparator_t* cmp) { + opt->rep.comparator = cmp; +} + +void leveldb_options_set_filter_policy( + leveldb_options_t* opt, + leveldb_filterpolicy_t* policy) { + opt->rep.filter_policy = policy; +} + +void leveldb_options_set_create_if_missing( + leveldb_options_t* opt, unsigned char v) { + opt->rep.create_if_missing = v; +} + +void leveldb_options_set_error_if_exists( + leveldb_options_t* opt, unsigned char v) { + opt->rep.error_if_exists = v; +} + +void leveldb_options_set_paranoid_checks( + leveldb_options_t* opt, unsigned char v) { + opt->rep.paranoid_checks = v; +} + +void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { + opt->rep.env = (env ? env->rep : NULL); +} + +void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { + opt->rep.info_log = (l ? l->rep : NULL); +} + +void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { + opt->rep.write_buffer_size = s; +} + +void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { + opt->rep.max_open_files = n; +} + +void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { + opt->rep.block_cache = c->rep; +} + +void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { + opt->rep.block_size = s; +} + +void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { + opt->rep.block_restart_interval = n; +} + +void leveldb_options_set_compression(leveldb_options_t* opt, int t) { + opt->rep.compression = static_cast(t); +} + +leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)) { + leveldb_comparator_t* result = new leveldb_comparator_t; + result->state_ = state; + result->destructor_ = destructor; + result->compare_ = compare; + result->name_ = name; + return result; +} + +void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { + delete cmp; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)) { + leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; + result->state_ = state; + result->destructor_ = destructor; + result->create_ = create_filter; + result->key_match_ = key_may_match; + result->name_ = name; + return result; +} + +void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { + delete filter; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { + // Make a leveldb_filterpolicy_t, but override all of its methods so + // they delegate to a NewBloomFilterPolicy() instead of user + // supplied C functions. + struct Wrapper : public leveldb_filterpolicy_t { + const FilterPolicy* rep_; + ~Wrapper() { delete rep_; } + const char* Name() const { return rep_->Name(); } + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + return rep_->CreateFilter(keys, n, dst); + } + bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return rep_->KeyMayMatch(key, filter); + } + static void DoNothing(void*) { } + }; + Wrapper* wrapper = new Wrapper; + wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); + wrapper->state_ = NULL; + wrapper->destructor_ = &Wrapper::DoNothing; + return wrapper; +} + +leveldb_readoptions_t* leveldb_readoptions_create() { + return new leveldb_readoptions_t; +} + +void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { + delete opt; +} + +void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t* opt, + unsigned char v) { + opt->rep.verify_checksums = v; +} + +void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t* opt, unsigned char v) { + opt->rep.fill_cache = v; +} + +void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t* opt, + const leveldb_snapshot_t* snap) { + opt->rep.snapshot = (snap ? snap->rep : NULL); +} + +leveldb_writeoptions_t* leveldb_writeoptions_create() { + return new leveldb_writeoptions_t; +} + +void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { + delete opt; +} + +void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t* opt, unsigned char v) { + opt->rep.sync = v; +} + +leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { + leveldb_cache_t* c = new leveldb_cache_t; + c->rep = NewLRUCache(capacity); + return c; +} + +void leveldb_cache_destroy(leveldb_cache_t* cache) { + delete cache->rep; + delete cache; +} + +leveldb_env_t* leveldb_create_default_env() { + leveldb_env_t* result = new leveldb_env_t; + result->rep = Env::Default(); + result->is_default = true; + return result; +} + +void leveldb_env_destroy(leveldb_env_t* env) { + if (!env->is_default) delete env->rep; + delete env; +} + +void leveldb_free(void* ptr) { + free(ptr); +} + +int leveldb_major_version() { + return kMajorVersion; +} + +int leveldb_minor_version() { + return kMinorVersion; +} + +} // end extern "C" diff --git a/db/c_test.c b/db/c_test.c new file mode 100644 index 000000000..7cd5ee020 --- /dev/null +++ b/db/c_test.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. */ + +#include "leveldb/c.h" + +#include +#include +#include +#include +#include +#include + +const char* phase = ""; +static char dbname[200]; + +static void StartPhase(const char* name) { + fprintf(stderr, "=== Test %s\n", name); + phase = name; +} + +static const char* GetTempDir(void) { + const char* ret = getenv("TEST_TMPDIR"); + if (ret == NULL || ret[0] == '\0') + ret = "/tmp"; + return ret; +} + +#define CheckNoError(err) \ + if ((err) != NULL) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ + abort(); \ + } + +#define CheckCondition(cond) \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ + abort(); \ + } + +static void CheckEqual(const char* expected, const char* v, size_t n) { + if (expected == NULL && v == NULL) { + // ok + } else if (expected != NULL && v != NULL && n == strlen(expected) && + memcmp(expected, v, n) == 0) { + // ok + return; + } else { + fprintf(stderr, "%s: expected '%s', got '%s'\n", + phase, + (expected ? expected : "(null)"), + (v ? v : "(null")); + abort(); + } +} + +static void Free(char** ptr) { + if (*ptr) { + free(*ptr); + *ptr = NULL; + } +} + +static void CheckGet( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, + const char* expected) { + char* err = NULL; + size_t val_len; + char* val; + val = leveldb_get(db, options, key, strlen(key), &val_len, &err); + CheckNoError(err); + CheckEqual(expected, val, val_len); + Free(&val); +} + +static void CheckIter(leveldb_iterator_t* iter, + const char* key, const char* val) { + size_t len; + const char* str; + str = leveldb_iter_key(iter, &len); + CheckEqual(key, str, len); + str = leveldb_iter_value(iter, &len); + CheckEqual(val, str, len); +} + +// Callback from leveldb_writebatch_iterate() +static void CheckPut(void* ptr, + const char* k, size_t klen, + const char* v, size_t vlen) { + int* state = (int*) ptr; + CheckCondition(*state < 2); + switch (*state) { + case 0: + CheckEqual("bar", k, klen); + CheckEqual("b", v, vlen); + break; + case 1: + CheckEqual("box", k, klen); + CheckEqual("c", v, vlen); + break; + } + (*state)++; +} + +// Callback from leveldb_writebatch_iterate() +static void CheckDel(void* ptr, const char* k, size_t klen) { + int* state = (int*) ptr; + CheckCondition(*state == 2); + CheckEqual("bar", k, klen); + (*state)++; +} + +static void CmpDestroy(void* arg) { } + +static int CmpCompare(void* arg, const char* a, size_t alen, + const char* b, size_t blen) { + int n = (alen < blen) ? alen : blen; + int r = memcmp(a, b, n); + if (r == 0) { + if (alen < blen) r = -1; + else if (alen > blen) r = +1; + } + return r; +} + +static const char* CmpName(void* arg) { + return "foo"; +} + +// Custom filter policy +static unsigned char fake_filter_result = 1; +static void FilterDestroy(void* arg) { } +static const char* FilterName(void* arg) { + return "TestFilter"; +} +static char* FilterCreate( + void* arg, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length) { + *filter_length = 4; + char* result = malloc(4); + memcpy(result, "fake", 4); + return result; +} +unsigned char FilterKeyMatch( + void* arg, + const char* key, size_t length, + const char* filter, size_t filter_length) { + CheckCondition(filter_length == 4); + CheckCondition(memcmp(filter, "fake", 4) == 0); + return fake_filter_result; +} + +int main(int argc, char** argv) { + leveldb_t* db; + leveldb_comparator_t* cmp; + leveldb_cache_t* cache; + leveldb_env_t* env; + leveldb_options_t* options; + leveldb_readoptions_t* roptions; + leveldb_writeoptions_t* woptions; + char* err = NULL; + int run = -1; + + CheckCondition(leveldb_major_version() >= 1); + CheckCondition(leveldb_minor_version() >= 1); + + snprintf(dbname, sizeof(dbname), + "%s/leveldb_c_test-%d", + GetTempDir(), + ((int) geteuid())); + + StartPhase("create_objects"); + cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); + env = leveldb_create_default_env(); + cache = leveldb_cache_create_lru(100000); + + options = leveldb_options_create(); + leveldb_options_set_comparator(options, cmp); + leveldb_options_set_error_if_exists(options, 1); + leveldb_options_set_cache(options, cache); + leveldb_options_set_env(options, env); + leveldb_options_set_info_log(options, NULL); + leveldb_options_set_write_buffer_size(options, 100000); + leveldb_options_set_paranoid_checks(options, 1); + leveldb_options_set_max_open_files(options, 10); + leveldb_options_set_block_size(options, 1024); + leveldb_options_set_block_restart_interval(options, 8); + leveldb_options_set_compression(options, leveldb_no_compression); + + roptions = leveldb_readoptions_create(); + leveldb_readoptions_set_verify_checksums(roptions, 1); + leveldb_readoptions_set_fill_cache(roptions, 0); + + woptions = leveldb_writeoptions_create(); + leveldb_writeoptions_set_sync(woptions, 1); + + StartPhase("destroy"); + leveldb_destroy_db(options, dbname, &err); + Free(&err); + + StartPhase("open_error"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + Free(&err); + + StartPhase("leveldb_free"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + leveldb_free(err); + err = NULL; + + StartPhase("open"); + leveldb_options_set_create_if_missing(options, 1); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + + StartPhase("put"); + leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactall"); + leveldb_compact_range(db, NULL, 0, NULL, 0); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactrange"); + leveldb_compact_range(db, "a", 1, "z", 1); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("writebatch"); + { + leveldb_writebatch_t* wb = leveldb_writebatch_create(); + leveldb_writebatch_put(wb, "foo", 3, "a", 1); + leveldb_writebatch_clear(wb); + leveldb_writebatch_put(wb, "bar", 3, "b", 1); + leveldb_writebatch_put(wb, "box", 3, "c", 1); + leveldb_writebatch_delete(wb, "bar", 3); + leveldb_write(db, woptions, wb, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + int pos = 0; + leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); + CheckCondition(pos == 3); + leveldb_writebatch_destroy(wb); + } + + StartPhase("iter"); + { + leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_first(iter); + CheckCondition(leveldb_iter_valid(iter)); + CheckIter(iter, "box", "c"); + leveldb_iter_next(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_prev(iter); + CheckIter(iter, "box", "c"); + leveldb_iter_prev(iter); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_last(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_seek(iter, "b", 1); + CheckIter(iter, "box", "c"); + leveldb_iter_get_error(iter, &err); + CheckNoError(err); + leveldb_iter_destroy(iter); + } + + StartPhase("approximate_sizes"); + { + int i; + int n = 20000; + char keybuf[100]; + char valbuf[100]; + uint64_t sizes[2]; + const char* start[2] = { "a", "k00000000000000010000" }; + size_t start_len[2] = { 1, 21 }; + const char* limit[2] = { "k00000000000000010000", "z" }; + size_t limit_len[2] = { 21, 1 }; + leveldb_writeoptions_set_sync(woptions, 0); + for (i = 0; i < n; i++) { + snprintf(keybuf, sizeof(keybuf), "k%020d", i); + snprintf(valbuf, sizeof(valbuf), "v%020d", i); + leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf), + &err); + CheckNoError(err); + } + leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes); + CheckCondition(sizes[0] > 0); + CheckCondition(sizes[1] > 0); + } + + StartPhase("property"); + { + char* prop = leveldb_property_value(db, "nosuchprop"); + CheckCondition(prop == NULL); + prop = leveldb_property_value(db, "leveldb.stats"); + CheckCondition(prop != NULL); + Free(&prop); + } + + StartPhase("snapshot"); + { + const leveldb_snapshot_t* snap; + snap = leveldb_create_snapshot(db); + leveldb_delete(db, woptions, "foo", 3, &err); + CheckNoError(err); + leveldb_readoptions_set_snapshot(roptions, snap); + CheckGet(db, roptions, "foo", "hello"); + leveldb_readoptions_set_snapshot(roptions, NULL); + CheckGet(db, roptions, "foo", NULL); + leveldb_release_snapshot(db, snap); + } + + StartPhase("repair"); + { + leveldb_close(db); + leveldb_options_set_create_if_missing(options, 0); + leveldb_options_set_error_if_exists(options, 0); + leveldb_repair_db(options, dbname, &err); + CheckNoError(err); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + leveldb_options_set_create_if_missing(options, 1); + leveldb_options_set_error_if_exists(options, 1); + } + + StartPhase("filter"); + for (run = 0; run < 2; run++) { + // First run uses custom filter, second run uses bloom filter + CheckNoError(err); + leveldb_filterpolicy_t* policy; + if (run == 0) { + policy = leveldb_filterpolicy_create( + NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName); + } else { + policy = leveldb_filterpolicy_create_bloom(10); + } + + // Create new database + leveldb_close(db); + leveldb_destroy_db(options, dbname, &err); + leveldb_options_set_filter_policy(options, policy); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err); + CheckNoError(err); + leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err); + CheckNoError(err); + leveldb_compact_range(db, NULL, 0, NULL, 0); + + fake_filter_result = 1; + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + if (phase == 0) { + // Must not find value when custom filter returns false + fake_filter_result = 0; + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + fake_filter_result = 1; + + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + } + leveldb_options_set_filter_policy(options, NULL); + leveldb_filterpolicy_destroy(policy); + } + + StartPhase("cleanup"); + leveldb_close(db); + leveldb_options_destroy(options); + leveldb_readoptions_destroy(roptions); + leveldb_writeoptions_destroy(woptions); + leveldb_cache_destroy(cache); + leveldb_comparator_destroy(cmp); + leveldb_env_destroy(env); + + fprintf(stderr, "PASS\n"); + return 0; +} diff --git a/db/corruption_test.cc b/db/corruption_test.cc new file mode 100644 index 000000000..31b2d5f41 --- /dev/null +++ b/db/corruption_test.cc @@ -0,0 +1,359 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include +#include +#include +#include +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/log_format.h" +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kValueSize = 1000; + +class CorruptionTest { + public: + test::ErrorEnv env_; + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + CorruptionTest() { + tiny_cache_ = NewLRUCache(100); + options_.env = &env_; + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, options_); + + db_ = NULL; + options_.create_if_missing = true; + Reopen(); + options_.create_if_missing = false; + } + + ~CorruptionTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + Status TryReopen(Options* options = NULL) { + delete db_; + db_ = NULL; + Options opt = (options ? *options : options_); + opt.env = &env_; + opt.block_cache = tiny_cache_; + return DB::Open(opt, dbname_, &db_); + } + + void Reopen(Options* options = NULL) { + ASSERT_OK(TryReopen(options)); + } + + void RepairDB() { + delete db_; + db_ = NULL; + ASSERT_OK(::leveldb::RepairDB(dbname_, options_)); + } + + void Build(int n) { + std::string key_space, value_space; + WriteBatch batch; + for (int i = 0; i < n; i++) { + //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n); + Slice key = Key(i, &key_space); + batch.Clear(); + batch.Put(key, Value(i, &value_space)); + ASSERT_OK(db_->Write(WriteOptions(), &batch)); + } + } + + void Check(int min_expected, int max_expected) { + int next_expected = 0; + int missed = 0; + int bad_keys = 0; + int bad_values = 0; + int correct = 0; + std::string value_space; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + uint64_t key; + Slice in(iter->key()); + if (!ConsumeDecimalNumber(&in, &key) || + !in.empty() || + key < next_expected) { + bad_keys++; + continue; + } + missed += (key - next_expected); + next_expected = key + 1; + if (iter->value() != Value(key, &value_space)) { + bad_values++; + } else { + correct++; + } + } + delete iter; + + fprintf(stderr, + "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n", + min_expected, max_expected, correct, bad_keys, bad_values, missed); + ASSERT_LE(min_expected, correct); + ASSERT_GE(max_expected, correct); + } + + void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) { + // Pick file to corrupt + std::vector filenames; + ASSERT_OK(env_.GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + std::string fname; + int picked_number = -1; + for (int i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type == filetype && + int(number) > picked_number) { // Pick latest file + fname = dbname_ + "/" + filenames[i]; + picked_number = number; + } + } + ASSERT_TRUE(!fname.empty()) << filetype; + + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + const char* msg = strerror(errno); + ASSERT_TRUE(false) << fname << ": " << msg; + } + + if (offset < 0) { + // Relative to end of file; make it absolute + if (-offset > sbuf.st_size) { + offset = 0; + } else { + offset = sbuf.st_size + offset; + } + } + if (offset > sbuf.st_size) { + offset = sbuf.st_size; + } + if (offset + bytes_to_corrupt > sbuf.st_size) { + bytes_to_corrupt = sbuf.st_size - offset; + } + + // Do it + std::string contents; + Status s = ReadFileToString(Env::Default(), fname, &contents); + ASSERT_TRUE(s.ok()) << s.ToString(); + for (int i = 0; i < bytes_to_corrupt; i++) { + contents[i + offset] ^= 0x80; + } + s = WriteStringToFile(Env::Default(), contents, fname); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + int Property(const std::string& name) { + std::string property; + int result; + if (db_->GetProperty(name, &property) && + sscanf(property.c_str(), "%d", &result) == 1) { + return result; + } else { + return -1; + } + } + + // Return the ith key + Slice Key(int i, std::string* storage) { + char buf[100]; + snprintf(buf, sizeof(buf), "%016d", i); + storage->assign(buf, strlen(buf)); + return Slice(*storage); + } + + // Return the value to associate with the specified key + Slice Value(int k, std::string* storage) { + Random r(k); + return test::RandomString(&r, kValueSize, storage); + } +}; + +TEST(CorruptionTest, Recovery) { + Build(100); + Check(100, 100); + Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record + Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block + Reopen(); + + // The 64 records in the first two log blocks are completely lost. + Check(36, 36); +} + +TEST(CorruptionTest, RecoverWriteError) { + env_.writable_file_error_ = true; + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); +} + +TEST(CorruptionTest, NewFileErrorDuringWrite) { + // Do enough writing to force minor compaction + env_.writable_file_error_ = true; + const int num = 3 + (Options().write_buffer_size / kValueSize); + std::string value_storage; + Status s; + for (int i = 0; s.ok() && i < num; i++) { + WriteBatch batch; + batch.Put("a", Value(100, &value_storage)); + s = db_->Write(WriteOptions(), &batch); + } + ASSERT_TRUE(!s.ok()); + ASSERT_GE(env_.num_writable_file_errors_, 1); + env_.writable_file_error_ = false; + Reopen(); +} + +TEST(CorruptionTest, TableFile) { + Build(100); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + dbi->TEST_CompactRange(1, NULL, NULL); + + Corrupt(kTableFile, 100, 1); + Check(99, 99); +} + +TEST(CorruptionTest, TableFileIndexData) { + Build(10000); // Enough to build multiple Tables + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + + Corrupt(kTableFile, -2000, 500); + Reopen(); + Check(5000, 9999); +} + +TEST(CorruptionTest, MissingDescriptor) { + Build(1000); + RepairDB(); + Reopen(); + Check(1000, 1000); +} + +TEST(CorruptionTest, SequenceNumberRecovery) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5")); + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v5", v); + // Write something. If sequence number was not recovered properly, + // it will be hidden by an earlier write. + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6")); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); + Reopen(); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); +} + +TEST(CorruptionTest, CorruptedDescriptor) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + + Corrupt(kDescriptorFile, 0, 1000); + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); + + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("hello", v); +} + +TEST(CorruptionTest, CompactionInputError) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); + + Corrupt(kTableFile, 100, 1); + Check(9, 9); + + // Force compactions by writing lots of values + Build(10000); + Check(10000, 10000); +} + +TEST(CorruptionTest, CompactionInputErrorParanoid) { + Options options; + options.paranoid_checks = true; + options.write_buffer_size = 1048576; + Reopen(&options); + DBImpl* dbi = reinterpret_cast(db_); + + // Fill levels >= 1 so memtable compaction outputs to level 1 + for (int level = 1; level < config::kNumLevels; level++) { + dbi->Put(WriteOptions(), "", "begin"); + dbi->Put(WriteOptions(), "~", "end"); + dbi->TEST_CompactMemTable(); + } + + Build(10); + dbi->TEST_CompactMemTable(); + ASSERT_EQ(1, Property("leveldb.num-files-at-level0")); + + Corrupt(kTableFile, 100, 1); + Check(9, 9); + + // Write must eventually fail because of corrupted table + Status s; + std::string tmp1, tmp2; + for (int i = 0; i < 10000 && s.ok(); i++) { + s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2)); + } + ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; +} + +TEST(CorruptionTest, UnrelatedKeys) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + + std::string tmp1, tmp2; + ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2))); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); + dbi->TEST_CompactMemTable(); + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/db_bench.cc b/db/db_bench.cc new file mode 100644 index 000000000..7abdf8758 --- /dev/null +++ b/db/db_bench.cc @@ -0,0 +1,979 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "db/db_impl.h" +#include "db/version_set.h" +#include "leveldb/cache.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/write_batch.h" +#include "port/port.h" +#include "util/crc32c.h" +#include "util/histogram.h" +#include "util/mutexlock.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillsync -- write N/100 values in random key order in sync mode +// fill100K -- write N/1000 100K values in random order in async mode +// deleteseq -- delete N keys in sequential order +// deleterandom -- delete N keys in random order +// readseq -- read N times sequentially +// readreverse -- read N times in reverse order +// readrandom -- read N times in random order +// readmissing -- read N missing keys in random order +// readhot -- read N times in random order from 1% section of DB +// seekrandom -- N random seeks +// crc32c -- repeated crc32c of 4K of data +// acquireload -- load N*1000 times +// Meta operations: +// compact -- Compact the entire DB +// stats -- Print DB stats +// sstables -- Print sstable info +// heapprofile -- Dump a heap profile (if supported by this port) +static const char* FLAGS_benchmarks = + "fillseq," + "fillsync," + "fillrandom," + "overwrite," + "readrandom," + "readrandom," // Extra run to allow previous compactions to quiesce + "readseq," + "readreverse," + "compact," + "readrandom," + "readseq," + "readreverse," + "fill100K," + "crc32c," + "snappycomp," + "snappyuncomp," + "acquireload," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Number of concurrent threads to run. +static int FLAGS_threads = 1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Number of bytes to buffer in memtable before compacting +// (initialized to default value by "main") +static int FLAGS_write_buffer_size = 0; + +// Number of bytes to use as a cache of uncompressed data. +// Negative means use default settings. +static int FLAGS_cache_size = -1; + +// Maximum number of files to keep open at the same time (use default if == 0) +static int FLAGS_open_files = 0; + +// Bloom filter bits per key. +// Negative means use default settings. +static int FLAGS_bloom_bits = -1; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +namespace leveldb { + +namespace { + +// Helper for quickly generating random data. +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +static void AppendWithSpace(std::string* str, Slice msg) { + if (msg.empty()) return; + if (!str->empty()) { + str->push_back(' '); + } + str->append(msg.data(), msg.size()); +} + +class Stats { + private: + double start_; + double finish_; + double seconds_; + int done_; + int next_report_; + int64_t bytes_; + double last_op_finish_; + Histogram hist_; + std::string message_; + + public: + Stats() { Start(); } + + void Start() { + next_report_ = 100; + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + bytes_ = 0; + seconds_ = 0; + start_ = Env::Default()->NowMicros(); + finish_ = start_; + message_.clear(); + } + + void Merge(const Stats& other) { + hist_.Merge(other.hist_); + done_ += other.done_; + bytes_ += other.bytes_; + seconds_ += other.seconds_; + if (other.start_ < start_) start_ = other.start_; + if (other.finish_ > finish_) finish_ = other.finish_; + + // Just keep the messages from one thread + if (message_.empty()) message_ = other.message_; + } + + void Stop() { + finish_ = Env::Default()->NowMicros(); + seconds_ = (finish_ - start_) * 1e-6; + } + + void AddMessage(Slice msg) { + AppendWithSpace(&message_, msg); + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros(); + double micros = now - last_op_finish_; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void AddBytes(int64_t n) { + bytes_ += n; + } + + void Report(const Slice& name) { + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + std::string extra; + if (bytes_ > 0) { + // Rate is computed on actual elapsed time, not the sum of per-thread + // elapsed times. + double elapsed = (finish_ - start_) * 1e-6; + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / elapsed); + extra = rate; + } + AppendWithSpace(&extra, message_); + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + seconds_ * 1e6 / done_, + (extra.empty() ? "" : " "), + extra.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } +}; + +// State shared by all concurrent executions of the same benchmark. +struct SharedState { + port::Mutex mu; + port::CondVar cv; + int total; + + // Each thread goes through the following states: + // (1) initializing + // (2) waiting for others to be initialized + // (3) running + // (4) done + + int num_initialized; + int num_done; + bool start; + + SharedState() : cv(&mu) { } +}; + +// Per-thread state for concurrent executions of the same benchmark. +struct ThreadState { + int tid; // 0..n-1 when running in n threads + Random rand; // Has different seeds for different threads + Stats stats; + SharedState* shared; + + ThreadState(int index) + : tid(index), + rand(1000 + index) { + } +}; + +} // namespace + +class Benchmark { + private: + Cache* cache_; + const FilterPolicy* filter_policy_; + DB* db_; + int num_; + int value_size_; + int entries_per_batch_; + WriteOptions write_options_; + int reads_; + int heap_counter_; + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + + // See if snappy is working by attempting to compress a compressible string + const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + std::string compressed; + if (!port::Snappy_Compress(text, sizeof(text), &compressed)) { + fprintf(stdout, "WARNING: Snappy compression is not enabled\n"); + } else if (compressed.size() >= sizeof(text)) { + fprintf(stdout, "WARNING: Snappy compression is not effective\n"); + } + } + + void PrintEnvironment() { + fprintf(stderr, "LevelDB: version %d.%d\n", + kMajorVersion, kMinorVersion); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + public: + Benchmark() + : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL), + filter_policy_(FLAGS_bloom_bits >= 0 + ? NewBloomFilterPolicy(FLAGS_bloom_bits) + : NULL), + db_(NULL), + num_(FLAGS_num), + value_size_(FLAGS_value_size), + entries_per_batch_(1), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + heap_counter_(0) { + std::vector files; + Env::Default()->GetChildren(FLAGS_db, &files); + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("heap-")) { + Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); + } + } + if (!FLAGS_use_existing_db) { + DestroyDB(FLAGS_db, Options()); + } + } + + ~Benchmark() { + delete db_; + delete cache_; + delete filter_policy_; + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + // Reset parameters that may be overriddden bwlow + num_ = FLAGS_num; + reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads); + value_size_ = FLAGS_value_size; + entries_per_batch_ = 1; + write_options_ = WriteOptions(); + + void (Benchmark::*method)(ThreadState*) = NULL; + bool fresh_db = false; + int num_threads = FLAGS_threads; + + if (name == Slice("fillseq")) { + fresh_db = true; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillbatch")) { + fresh_db = true; + entries_per_batch_ = 1000; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillrandom")) { + fresh_db = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("overwrite")) { + fresh_db = false; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fillsync")) { + fresh_db = true; + num_ /= 1000; + write_options_.sync = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fill100K")) { + fresh_db = true; + num_ /= 1000; + value_size_ = 100 * 1000; + method = &Benchmark::WriteRandom; + } else if (name == Slice("readseq")) { + method = &Benchmark::ReadSequential; + } else if (name == Slice("readreverse")) { + method = &Benchmark::ReadReverse; + } else if (name == Slice("readrandom")) { + method = &Benchmark::ReadRandom; + } else if (name == Slice("readmissing")) { + method = &Benchmark::ReadMissing; + } else if (name == Slice("seekrandom")) { + method = &Benchmark::SeekRandom; + } else if (name == Slice("readhot")) { + method = &Benchmark::ReadHot; + } else if (name == Slice("readrandomsmall")) { + reads_ /= 1000; + method = &Benchmark::ReadRandom; + } else if (name == Slice("deleteseq")) { + method = &Benchmark::DeleteSeq; + } else if (name == Slice("deleterandom")) { + method = &Benchmark::DeleteRandom; + } else if (name == Slice("readwhilewriting")) { + num_threads++; // Add extra thread for writing + method = &Benchmark::ReadWhileWriting; + } else if (name == Slice("compact")) { + method = &Benchmark::Compact; + } else if (name == Slice("crc32c")) { + method = &Benchmark::Crc32c; + } else if (name == Slice("acquireload")) { + method = &Benchmark::AcquireLoad; + } else if (name == Slice("snappycomp")) { + method = &Benchmark::SnappyCompress; + } else if (name == Slice("snappyuncomp")) { + method = &Benchmark::SnappyUncompress; + } else if (name == Slice("heapprofile")) { + HeapProfile(); + } else if (name == Slice("stats")) { + PrintStats("leveldb.stats"); + } else if (name == Slice("sstables")) { + PrintStats("leveldb.sstables"); + } else { + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + + if (fresh_db) { + if (FLAGS_use_existing_db) { + fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n", + name.ToString().c_str()); + method = NULL; + } else { + delete db_; + db_ = NULL; + DestroyDB(FLAGS_db, Options()); + Open(); + } + } + + if (method != NULL) { + RunBenchmark(num_threads, name, method); + } + } + } + + private: + struct ThreadArg { + Benchmark* bm; + SharedState* shared; + ThreadState* thread; + void (Benchmark::*method)(ThreadState*); + }; + + static void ThreadBody(void* v) { + ThreadArg* arg = reinterpret_cast(v); + SharedState* shared = arg->shared; + ThreadState* thread = arg->thread; + { + MutexLock l(&shared->mu); + shared->num_initialized++; + if (shared->num_initialized >= shared->total) { + shared->cv.SignalAll(); + } + while (!shared->start) { + shared->cv.Wait(); + } + } + + thread->stats.Start(); + (arg->bm->*(arg->method))(thread); + thread->stats.Stop(); + + { + MutexLock l(&shared->mu); + shared->num_done++; + if (shared->num_done >= shared->total) { + shared->cv.SignalAll(); + } + } + } + + void RunBenchmark(int n, Slice name, + void (Benchmark::*method)(ThreadState*)) { + SharedState shared; + shared.total = n; + shared.num_initialized = 0; + shared.num_done = 0; + shared.start = false; + + ThreadArg* arg = new ThreadArg[n]; + for (int i = 0; i < n; i++) { + arg[i].bm = this; + arg[i].method = method; + arg[i].shared = &shared; + arg[i].thread = new ThreadState(i); + arg[i].thread->shared = &shared; + Env::Default()->StartThread(ThreadBody, &arg[i]); + } + + shared.mu.Lock(); + while (shared.num_initialized < n) { + shared.cv.Wait(); + } + + shared.start = true; + shared.cv.SignalAll(); + while (shared.num_done < n) { + shared.cv.Wait(); + } + shared.mu.Unlock(); + + for (int i = 1; i < n; i++) { + arg[0].thread->stats.Merge(arg[i].thread->stats); + } + arg[0].thread->stats.Report(name); + + for (int i = 0; i < n; i++) { + delete arg[i].thread; + } + delete[] arg; + } + + void Crc32c(ThreadState* thread) { + // Checksum about 500MB of data total + const int size = 4096; + const char* label = "(4K per op)"; + std::string data(size, 'x'); + int64_t bytes = 0; + uint32_t crc = 0; + while (bytes < 500 * 1048576) { + crc = crc32c::Value(data.data(), size); + thread->stats.FinishedSingleOp(); + bytes += size; + } + // Print so result is not dead + fprintf(stderr, "... crc=0x%x\r", static_cast(crc)); + + thread->stats.AddBytes(bytes); + thread->stats.AddMessage(label); + } + + void AcquireLoad(ThreadState* thread) { + int dummy; + port::AtomicPointer ap(&dummy); + int count = 0; + void *ptr = NULL; + thread->stats.AddMessage("(each op is 1000 loads)"); + while (count < 100000) { + for (int i = 0; i < 1000; i++) { + ptr = ap.Acquire_Load(); + } + count++; + thread->stats.FinishedSingleOp(); + } + if (ptr == NULL) exit(1); // Disable unused variable warning. + } + + void SnappyCompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + int64_t bytes = 0; + int64_t produced = 0; + bool ok = true; + std::string compressed; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + produced += compressed.size(); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "(output: %.1f%%)", + (produced * 100.0) / bytes); + thread->stats.AddMessage(buf); + thread->stats.AddBytes(bytes); + } + } + + void SnappyUncompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + std::string compressed; + bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + int64_t bytes = 0; + char* uncompressed = new char[input.size()]; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Uncompress(compressed.data(), compressed.size(), + uncompressed); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + delete[] uncompressed; + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + thread->stats.AddBytes(bytes); + } + } + + void Open() { + assert(db_ == NULL); + Options options; + options.create_if_missing = !FLAGS_use_existing_db; + options.block_cache = cache_; + options.write_buffer_size = FLAGS_write_buffer_size; + options.max_open_files = FLAGS_open_files; + options.filter_policy = filter_policy_; + Status s = DB::Open(options, FLAGS_db, &db_); + if (!s.ok()) { + fprintf(stderr, "open error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + void WriteSeq(ThreadState* thread) { + DoWrite(thread, true); + } + + void WriteRandom(ThreadState* thread) { + DoWrite(thread, false); + } + + void DoWrite(ThreadState* thread, bool seq) { + if (num_ != FLAGS_num) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_); + thread->stats.AddMessage(msg); + } + + RandomGenerator gen; + WriteBatch batch; + Status s; + int64_t bytes = 0; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Put(key, gen.Generate(value_size_)); + bytes += value_size_ + strlen(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + thread->stats.AddBytes(bytes); + } + + void ReadSequential(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadReverse(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadRandom(ThreadState* thread) { + ReadOptions options; + std::string value; + int found = 0; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + if (db_->Get(options, key, &value).ok()) { + found++; + } + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void ReadMissing(ThreadState* thread) { + ReadOptions options; + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d.", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void ReadHot(ThreadState* thread) { + ReadOptions options; + std::string value; + const int range = (FLAGS_num + 99) / 100; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % range; + snprintf(key, sizeof(key), "%016d", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void SeekRandom(ThreadState* thread) { + ReadOptions options; + std::string value; + int found = 0; + for (int i = 0; i < reads_; i++) { + Iterator* iter = db_->NewIterator(options); + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + iter->Seek(key); + if (iter->Valid() && iter->key() == key) found++; + delete iter; + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void DoDelete(ThreadState* thread, bool seq) { + RandomGenerator gen; + WriteBatch batch; + Status s; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Delete(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "del error: %s\n", s.ToString().c_str()); + exit(1); + } + } + } + + void DeleteSeq(ThreadState* thread) { + DoDelete(thread, true); + } + + void DeleteRandom(ThreadState* thread) { + DoDelete(thread, false); + } + + void ReadWhileWriting(ThreadState* thread) { + if (thread->tid > 0) { + ReadRandom(thread); + } else { + // Special thread that keeps writing until other threads are done. + RandomGenerator gen; + while (true) { + { + MutexLock l(&thread->shared->mu); + if (thread->shared->num_done + 1 >= thread->shared->num_initialized) { + // Other threads have finished + break; + } + } + + const int k = thread->rand.Next() % FLAGS_num; + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + Status s = db_->Put(write_options_, key, gen.Generate(value_size_)); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + // Do not count any of the preceding work/delay in stats. + thread->stats.Start(); + } + } + + void Compact(ThreadState* thread) { + db_->CompactRange(NULL, NULL); + } + + void PrintStats(const char* key) { + std::string stats; + if (!db_->GetProperty(key, &stats)) { + stats = "(failed)"; + } + fprintf(stdout, "\n%s\n", stats.c_str()); + } + + static void WriteToFile(void* arg, const char* buf, int n) { + reinterpret_cast(arg)->Append(Slice(buf, n)); + } + + void HeapProfile() { + char fname[100]; + snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); + WritableFile* file; + Status s = Env::Default()->NewWritableFile(fname, &file); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + return; + } + bool ok = port::GetHeapProfile(WriteToFile, file); + delete file; + if (!ok) { + fprintf(stderr, "heap profiling not supported\n"); + Env::Default()->DeleteFile(fname); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; + FLAGS_open_files = leveldb::Options().max_open_files; + std::string default_db_path; + + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_use_existing_db = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) { + FLAGS_threads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { + FLAGS_write_buffer_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { + FLAGS_bloom_bits = n; + } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) { + FLAGS_open_files = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/db/db_impl.cc b/db/db_impl.cc new file mode 100644 index 000000000..c9de169f2 --- /dev/null +++ b/db/db_impl.cc @@ -0,0 +1,1467 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" + +#include +#include +#include +#include +#include +#include +#include "db/builder.h" +#include "db/db_iter.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/table_builder.h" +#include "port/port.h" +#include "table/block.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" +#include "util/mutexlock.h" + +namespace leveldb { + +// Information kept for every waiting writer +struct DBImpl::Writer { + Status status; + WriteBatch* batch; + bool sync; + bool done; + port::CondVar cv; + + explicit Writer(port::Mutex* mu) : cv(mu) { } +}; + +struct DBImpl::CompactionState { + Compaction* const compaction; + + // Sequence numbers < smallest_snapshot are not significant since we + // will never have to service a snapshot below smallest_snapshot. + // Therefore if we have seen a sequence number S <= smallest_snapshot, + // we can drop all entries for the same key with sequence numbers < S. + SequenceNumber smallest_snapshot; + + // Files produced by compaction + struct Output { + uint64_t number; + uint64_t file_size; + InternalKey smallest, largest; + }; + std::vector outputs; + + // State kept for output being generated + WritableFile* outfile; + TableBuilder* builder; + + uint64_t total_bytes; + + Output* current_output() { return &outputs[outputs.size()-1]; } + + explicit CompactionState(Compaction* c) + : compaction(c), + outfile(NULL), + builder(NULL), + total_bytes(0) { + } +}; + +// Fix user-supplied options to be reasonable +template +static void ClipToRange(T* ptr, V minvalue, V maxvalue) { + if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; + if (static_cast(*ptr) < minvalue) *ptr = minvalue; +} +Options SanitizeOptions(const std::string& dbname, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src) { + Options result = src; + result.comparator = icmp; + result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; + ClipToRange(&result.max_open_files, 20, 50000); + ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.block_size, 1<<10, 4<<20); + if (result.info_log == NULL) { + // Open a log file in the same directory as the db + src.env->CreateDir(dbname); // In case it does not exist + src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); + Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); + if (!s.ok()) { + // No place suitable for logging + result.info_log = NULL; + } + } + if (result.block_cache == NULL) { + result.block_cache = NewLRUCache(8 << 20); + } + return result; +} + +DBImpl::DBImpl(const Options& options, const std::string& dbname) + : env_(options.env), + internal_comparator_(options.comparator), + internal_filter_policy_(options.filter_policy), + options_(SanitizeOptions( + dbname, &internal_comparator_, &internal_filter_policy_, options)), + owns_info_log_(options_.info_log != options.info_log), + owns_cache_(options_.block_cache != options.block_cache), + dbname_(dbname), + db_lock_(NULL), + shutting_down_(NULL), + bg_cv_(&mutex_), + mem_(new MemTable(internal_comparator_)), + imm_(NULL), + logfile_(NULL), + logfile_number_(0), + log_(NULL), + tmp_batch_(new WriteBatch), + bg_compaction_scheduled_(false), + manual_compaction_(NULL) { + mem_->Ref(); + has_imm_.Release_Store(NULL); + + // Reserve ten files or so for other uses and give the rest to TableCache. + const int table_cache_size = options.max_open_files - 10; + table_cache_ = new TableCache(dbname_, &options_, table_cache_size); + + versions_ = new VersionSet(dbname_, &options_, table_cache_, + &internal_comparator_); +} + +DBImpl::~DBImpl() { + // Wait for background work to finish + mutex_.Lock(); + shutting_down_.Release_Store(this); // Any non-NULL value is ok + while (bg_compaction_scheduled_) { + bg_cv_.Wait(); + } + mutex_.Unlock(); + + if (db_lock_ != NULL) { + env_->UnlockFile(db_lock_); + } + + delete versions_; + if (mem_ != NULL) mem_->Unref(); + if (imm_ != NULL) imm_->Unref(); + delete tmp_batch_; + delete log_; + delete logfile_; + delete table_cache_; + + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } +} + +Status DBImpl::NewDB() { + VersionEdit new_db; + new_db.SetComparatorName(user_comparator()->Name()); + new_db.SetLogNumber(0); + new_db.SetNextFile(2); + new_db.SetLastSequence(0); + + const std::string manifest = DescriptorFileName(dbname_, 1); + WritableFile* file; + Status s = env_->NewWritableFile(manifest, &file); + if (!s.ok()) { + return s; + } + { + log::Writer log(file); + std::string record; + new_db.EncodeTo(&record); + s = log.AddRecord(record); + if (s.ok()) { + s = file->Close(); + } + } + delete file; + if (s.ok()) { + // Make "CURRENT" file that points to the new manifest file. + s = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(manifest); + } + return s; +} + +void DBImpl::MaybeIgnoreError(Status* s) const { + if (s->ok() || options_.paranoid_checks) { + // No change needed + } else { + Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); + *s = Status::OK(); + } +} + +void DBImpl::DeleteObsoleteFiles() { + // Make a set of all of the live files + std::set live = pending_outputs_; + versions_->AddLiveFiles(&live); + + std::vector filenames; + env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + bool keep = true; + switch (type) { + case kLogFile: + keep = ((number >= versions_->LogNumber()) || + (number == versions_->PrevLogNumber())); + break; + case kDescriptorFile: + // Keep my manifest file, and any newer incarnations' + // (in case there is a race that allows other incarnations) + keep = (number >= versions_->ManifestFileNumber()); + break; + case kTableFile: + keep = (live.find(number) != live.end()); + break; + case kTempFile: + // Any temp files that are currently being written to must + // be recorded in pending_outputs_, which is inserted into "live" + keep = (live.find(number) != live.end()); + break; + case kCurrentFile: + case kDBLockFile: + case kInfoLogFile: + keep = true; + break; + } + + if (!keep) { + if (type == kTableFile) { + table_cache_->Evict(number); + } + Log(options_.info_log, "Delete type=%d #%lld\n", + int(type), + static_cast(number)); + env_->DeleteFile(dbname_ + "/" + filenames[i]); + } + } + } +} + +Status DBImpl::Recover(VersionEdit* edit) { + mutex_.AssertHeld(); + + // Ignore error from CreateDir since the creation of the DB is + // committed only when the descriptor is created, and this directory + // may already exist from a previous failed creation attempt. + env_->CreateDir(dbname_); + assert(db_lock_ == NULL); + Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); + if (!s.ok()) { + return s; + } + + if (!env_->FileExists(CurrentFileName(dbname_))) { + if (options_.create_if_missing) { + s = NewDB(); + if (!s.ok()) { + return s; + } + } else { + return Status::InvalidArgument( + dbname_, "does not exist (create_if_missing is false)"); + } + } else { + if (options_.error_if_exists) { + return Status::InvalidArgument( + dbname_, "exists (error_if_exists is true)"); + } + } + + s = versions_->Recover(); + if (s.ok()) { + SequenceNumber max_sequence(0); + + // Recover from all newer log files than the ones named in the + // descriptor (new log files may have been added by the previous + // incarnation without registering them in the descriptor). + // + // Note that PrevLogNumber() is no longer used, but we pay + // attention to it in case we are recovering a database + // produced by an older version of leveldb. + const uint64_t min_log = versions_->LogNumber(); + const uint64_t prev_log = versions_->PrevLogNumber(); + std::vector filenames; + s = env_->GetChildren(dbname_, &filenames); + if (!s.ok()) { + return s; + } + uint64_t number; + FileType type; + std::vector logs; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) + && type == kLogFile + && ((number >= min_log) || (number == prev_log))) { + logs.push_back(number); + } + } + + // Recover in the order in which the logs were generated + std::sort(logs.begin(), logs.end()); + for (size_t i = 0; i < logs.size(); i++) { + s = RecoverLogFile(logs[i], edit, &max_sequence); + + // The previous incarnation may not have written any MANIFEST + // records after allocating this log number. So we manually + // update the file number allocation counter in VersionSet. + versions_->MarkFileNumberUsed(logs[i]); + } + + if (s.ok()) { + if (versions_->LastSequence() < max_sequence) { + versions_->SetLastSequence(max_sequence); + } + } + } + + return s; +} + +Status DBImpl::RecoverLogFile(uint64_t log_number, + VersionEdit* edit, + SequenceNumber* max_sequence) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + const char* fname; + Status* status; // NULL if options_.paranoid_checks==false + virtual void Corruption(size_t bytes, const Status& s) { + Log(info_log, "%s%s: dropping %d bytes; %s", + (this->status == NULL ? "(ignoring error) " : ""), + fname, static_cast(bytes), s.ToString().c_str()); + if (this->status != NULL && this->status->ok()) *this->status = s; + } + }; + + mutex_.AssertHeld(); + + // Open the log file + std::string fname = LogFileName(dbname_, log_number); + SequentialFile* file; + Status status = env_->NewSequentialFile(fname, &file); + if (!status.ok()) { + MaybeIgnoreError(&status); + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.fname = fname.c_str(); + reporter.status = (options_.paranoid_checks ? &status : NULL); + // We intentially make log::Reader do checksumming even if + // paranoid_checks==false so that corruptions cause entire commits + // to be skipped instead of propagating bad information (like overly + // large sequence numbers). + log::Reader reader(file, &reporter, true/*checksum*/, + 0/*initial_offset*/); + Log(options_.info_log, "Recovering log #%llu", + (unsigned long long) log_number); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = NULL; + while (reader.ReadRecord(&record, &scratch) && + status.ok()) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + + if (mem == NULL) { + mem = new MemTable(internal_comparator_); + mem->Ref(); + } + status = WriteBatchInternal::InsertInto(&batch, mem); + MaybeIgnoreError(&status); + if (!status.ok()) { + break; + } + const SequenceNumber last_seq = + WriteBatchInternal::Sequence(&batch) + + WriteBatchInternal::Count(&batch) - 1; + if (last_seq > *max_sequence) { + *max_sequence = last_seq; + } + + if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { + status = WriteLevel0Table(mem, edit, NULL); + if (!status.ok()) { + // Reflect errors immediately so that conditions like full + // file-systems cause the DB::Open() to fail. + break; + } + mem->Unref(); + mem = NULL; + } + } + + if (status.ok() && mem != NULL) { + status = WriteLevel0Table(mem, edit, NULL); + // Reflect errors immediately so that conditions like full + // file-systems cause the DB::Open() to fail. + } + + if (mem != NULL) mem->Unref(); + delete file; + return status; +} + +Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, + Version* base) { + mutex_.AssertHeld(); + const uint64_t start_micros = env_->NowMicros(); + FileMetaData meta; + meta.number = versions_->NewFileNumber(); + pending_outputs_.insert(meta.number); + Iterator* iter = mem->NewIterator(); + Log(options_.info_log, "Level-0 table #%llu: started", + (unsigned long long) meta.number); + + Status s; + { + mutex_.Unlock(); + s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + mutex_.Lock(); + } + + Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", + (unsigned long long) meta.number, + (unsigned long long) meta.file_size, + s.ToString().c_str()); + delete iter; + pending_outputs_.erase(meta.number); + + + // Note that if file_size is zero, the file has been deleted and + // should not be added to the manifest. + int level = 0; + if (s.ok() && meta.file_size > 0) { + const Slice min_user_key = meta.smallest.user_key(); + const Slice max_user_key = meta.largest.user_key(); + if (base != NULL) { + level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); + } + edit->AddFile(level, meta.number, meta.file_size, + meta.smallest, meta.largest); + } + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros; + stats.bytes_written = meta.file_size; + stats_[level].Add(stats); + return s; +} + +Status DBImpl::CompactMemTable() { + mutex_.AssertHeld(); + assert(imm_ != NULL); + + // Save the contents of the memtable as a new Table + VersionEdit edit; + Version* base = versions_->current(); + base->Ref(); + Status s = WriteLevel0Table(imm_, &edit, base); + base->Unref(); + + if (s.ok() && shutting_down_.Acquire_Load()) { + s = Status::IOError("Deleting DB during memtable compaction"); + } + + // Replace immutable memtable with the generated Table + if (s.ok()) { + edit.SetPrevLogNumber(0); + edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed + s = versions_->LogAndApply(&edit, &mutex_); + } + + if (s.ok()) { + // Commit to the new state + imm_->Unref(); + imm_ = NULL; + has_imm_.Release_Store(NULL); + DeleteObsoleteFiles(); + } + + return s; +} + +void DBImpl::CompactRange(const Slice* begin, const Slice* end) { + int max_level_with_files = 1; + { + MutexLock l(&mutex_); + Version* base = versions_->current(); + for (int level = 1; level < config::kNumLevels; level++) { + if (base->OverlapInLevel(level, begin, end)) { + max_level_with_files = level; + } + } + } + TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap + for (int level = 0; level < max_level_with_files; level++) { + TEST_CompactRange(level, begin, end); + } +} + +void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) { + assert(level >= 0); + assert(level + 1 < config::kNumLevels); + + InternalKey begin_storage, end_storage; + + ManualCompaction manual; + manual.level = level; + manual.done = false; + if (begin == NULL) { + manual.begin = NULL; + } else { + begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); + manual.begin = &begin_storage; + } + if (end == NULL) { + manual.end = NULL; + } else { + end_storage = InternalKey(*end, 0, static_cast(0)); + manual.end = &end_storage; + } + + MutexLock l(&mutex_); + while (!manual.done) { + while (manual_compaction_ != NULL) { + bg_cv_.Wait(); + } + manual_compaction_ = &manual; + MaybeScheduleCompaction(); + while (manual_compaction_ == &manual) { + bg_cv_.Wait(); + } + } +} + +Status DBImpl::TEST_CompactMemTable() { + // NULL batch means just wait for earlier writes to be done + Status s = Write(WriteOptions(), NULL); + if (s.ok()) { + // Wait until the compaction completes + MutexLock l(&mutex_); + while (imm_ != NULL && bg_error_.ok()) { + bg_cv_.Wait(); + } + if (imm_ != NULL) { + s = bg_error_; + } + } + return s; +} + +void DBImpl::MaybeScheduleCompaction() { + mutex_.AssertHeld(); + if (bg_compaction_scheduled_) { + // Already scheduled + } else if (shutting_down_.Acquire_Load()) { + // DB is being deleted; no more background compactions + } else if (imm_ == NULL && + manual_compaction_ == NULL && + !versions_->NeedsCompaction()) { + // No work to be done + } else { + bg_compaction_scheduled_ = true; + env_->Schedule(&DBImpl::BGWork, this); + } +} + +void DBImpl::BGWork(void* db) { + reinterpret_cast(db)->BackgroundCall(); +} + +void DBImpl::BackgroundCall() { + MutexLock l(&mutex_); + assert(bg_compaction_scheduled_); + if (!shutting_down_.Acquire_Load()) { + Status s = BackgroundCompaction(); + if (s.ok()) { + // Success + } else if (shutting_down_.Acquire_Load()) { + // Error most likely due to shutdown; do not wait + } else { + // Wait a little bit before retrying background compaction in + // case this is an environmental problem and we do not want to + // chew up resources for failed compactions for the duration of + // the problem. + bg_cv_.SignalAll(); // In case a waiter can proceed despite the error + Log(options_.info_log, "Waiting after background compaction error: %s", + s.ToString().c_str()); + mutex_.Unlock(); + env_->SleepForMicroseconds(1000000); + mutex_.Lock(); + } + } + + bg_compaction_scheduled_ = false; + + // Previous compaction may have produced too many files in a level, + // so reschedule another compaction if needed. + MaybeScheduleCompaction(); + bg_cv_.SignalAll(); +} + +Status DBImpl::BackgroundCompaction() { + mutex_.AssertHeld(); + + if (imm_ != NULL) { + return CompactMemTable(); + } + + Compaction* c; + bool is_manual = (manual_compaction_ != NULL); + InternalKey manual_end; + if (is_manual) { + ManualCompaction* m = manual_compaction_; + c = versions_->CompactRange(m->level, m->begin, m->end); + m->done = (c == NULL); + if (c != NULL) { + manual_end = c->input(0, c->num_input_files(0) - 1)->largest; + } + Log(options_.info_log, + "Manual compaction at level-%d from %s .. %s; will stop at %s\n", + m->level, + (m->begin ? m->begin->DebugString().c_str() : "(begin)"), + (m->end ? m->end->DebugString().c_str() : "(end)"), + (m->done ? "(end)" : manual_end.DebugString().c_str())); + } else { + c = versions_->PickCompaction(); + } + + Status status; + if (c == NULL) { + // Nothing to do + } else if (!is_manual && c->IsTrivialMove()) { + // Move file to next level + assert(c->num_input_files(0) == 1); + FileMetaData* f = c->input(0, 0); + c->edit()->DeleteFile(c->level(), f->number); + c->edit()->AddFile(c->level() + 1, f->number, f->file_size, + f->smallest, f->largest); + status = versions_->LogAndApply(c->edit(), &mutex_); + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", + static_cast(f->number), + c->level() + 1, + static_cast(f->file_size), + status.ToString().c_str(), + versions_->LevelSummary(&tmp)); + } else { + CompactionState* compact = new CompactionState(c); + status = DoCompactionWork(compact); + CleanupCompaction(compact); + c->ReleaseInputs(); + DeleteObsoleteFiles(); + } + delete c; + + if (status.ok()) { + // Done + } else if (shutting_down_.Acquire_Load()) { + // Ignore compaction errors found during shutting down + } else { + Log(options_.info_log, + "Compaction error: %s", status.ToString().c_str()); + if (options_.paranoid_checks && bg_error_.ok()) { + bg_error_ = status; + } + } + + if (is_manual) { + ManualCompaction* m = manual_compaction_; + if (!status.ok()) { + m->done = true; + } + if (!m->done) { + // We only compacted part of the requested range. Update *m + // to the range that is left to be compacted. + m->tmp_storage = manual_end; + m->begin = &m->tmp_storage; + } + manual_compaction_ = NULL; + } + return status; +} + +void DBImpl::CleanupCompaction(CompactionState* compact) { + mutex_.AssertHeld(); + if (compact->builder != NULL) { + // May happen if we get a shutdown call in the middle of compaction + compact->builder->Abandon(); + delete compact->builder; + } else { + assert(compact->outfile == NULL); + } + delete compact->outfile; + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + pending_outputs_.erase(out.number); + } + delete compact; +} + +Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { + assert(compact != NULL); + assert(compact->builder == NULL); + uint64_t file_number; + { + mutex_.Lock(); + file_number = versions_->NewFileNumber(); + pending_outputs_.insert(file_number); + CompactionState::Output out; + out.number = file_number; + out.smallest.Clear(); + out.largest.Clear(); + compact->outputs.push_back(out); + mutex_.Unlock(); + } + + // Make the output file + std::string fname = TableFileName(dbname_, file_number); + Status s = env_->NewWritableFile(fname, &compact->outfile); + if (s.ok()) { + compact->builder = new TableBuilder(options_, compact->outfile); + } + return s; +} + +Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, + Iterator* input) { + assert(compact != NULL); + assert(compact->outfile != NULL); + assert(compact->builder != NULL); + + const uint64_t output_number = compact->current_output()->number; + assert(output_number != 0); + + // Check for iterator errors + Status s = input->status(); + const uint64_t current_entries = compact->builder->NumEntries(); + if (s.ok()) { + s = compact->builder->Finish(); + } else { + compact->builder->Abandon(); + } + const uint64_t current_bytes = compact->builder->FileSize(); + compact->current_output()->file_size = current_bytes; + compact->total_bytes += current_bytes; + delete compact->builder; + compact->builder = NULL; + + // Finish and check for file errors + if (s.ok()) { + s = compact->outfile->Sync(); + } + if (s.ok()) { + s = compact->outfile->Close(); + } + delete compact->outfile; + compact->outfile = NULL; + + if (s.ok() && current_entries > 0) { + // Verify that the table is usable + Iterator* iter = table_cache_->NewIterator(ReadOptions(), + output_number, + current_bytes); + s = iter->status(); + delete iter; + if (s.ok()) { + Log(options_.info_log, + "Generated table #%llu: %lld keys, %lld bytes", + (unsigned long long) output_number, + (unsigned long long) current_entries, + (unsigned long long) current_bytes); + } + } + return s; +} + + +Status DBImpl::InstallCompactionResults(CompactionState* compact) { + mutex_.AssertHeld(); + Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1, + static_cast(compact->total_bytes)); + + // Add compaction outputs + compact->compaction->AddInputDeletions(compact->compaction->edit()); + const int level = compact->compaction->level(); + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + compact->compaction->edit()->AddFile( + level + 1, + out.number, out.file_size, out.smallest, out.largest); + } + return versions_->LogAndApply(compact->compaction->edit(), &mutex_); +} + +Status DBImpl::DoCompactionWork(CompactionState* compact) { + const uint64_t start_micros = env_->NowMicros(); + int64_t imm_micros = 0; // Micros spent doing imm_ compactions + + Log(options_.info_log, "Compacting %d@%d + %d@%d files", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1); + + assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); + assert(compact->builder == NULL); + assert(compact->outfile == NULL); + if (snapshots_.empty()) { + compact->smallest_snapshot = versions_->LastSequence(); + } else { + compact->smallest_snapshot = snapshots_.oldest()->number_; + } + + // Release mutex while we're actually doing the compaction work + mutex_.Unlock(); + + Iterator* input = versions_->MakeInputIterator(compact->compaction); + input->SeekToFirst(); + Status status; + ParsedInternalKey ikey; + std::string current_user_key; + bool has_current_user_key = false; + SequenceNumber last_sequence_for_key = kMaxSequenceNumber; + for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { + // Prioritize immutable compaction work + if (has_imm_.NoBarrier_Load() != NULL) { + const uint64_t imm_start = env_->NowMicros(); + mutex_.Lock(); + if (imm_ != NULL) { + CompactMemTable(); + bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary + } + mutex_.Unlock(); + imm_micros += (env_->NowMicros() - imm_start); + } + + Slice key = input->key(); + if (compact->compaction->ShouldStopBefore(key) && + compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + + // Handle key/value, add to state, etc. + bool drop = false; + if (!ParseInternalKey(key, &ikey)) { + // Do not hide error keys + current_user_key.clear(); + has_current_user_key = false; + last_sequence_for_key = kMaxSequenceNumber; + } else { + if (!has_current_user_key || + user_comparator()->Compare(ikey.user_key, + Slice(current_user_key)) != 0) { + // First occurrence of this user key + current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); + has_current_user_key = true; + last_sequence_for_key = kMaxSequenceNumber; + } + + if (last_sequence_for_key <= compact->smallest_snapshot) { + // Hidden by an newer entry for same user key + drop = true; // (A) + } else if (ikey.type == kTypeDeletion && + ikey.sequence <= compact->smallest_snapshot && + compact->compaction->IsBaseLevelForKey(ikey.user_key)) { + // For this user key: + // (1) there is no data in higher levels + // (2) data in lower levels will have larger sequence numbers + // (3) data in layers that are being compacted here and have + // smaller sequence numbers will be dropped in the next + // few iterations of this loop (by rule (A) above). + // Therefore this deletion marker is obsolete and can be dropped. + drop = true; + } + + last_sequence_for_key = ikey.sequence; + } +#if 0 + Log(options_.info_log, + " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " + "%d smallest_snapshot: %d", + ikey.user_key.ToString().c_str(), + (int)ikey.sequence, ikey.type, kTypeValue, drop, + compact->compaction->IsBaseLevelForKey(ikey.user_key), + (int)last_sequence_for_key, (int)compact->smallest_snapshot); +#endif + + if (!drop) { + // Open output file if necessary + if (compact->builder == NULL) { + status = OpenCompactionOutputFile(compact); + if (!status.ok()) { + break; + } + } + if (compact->builder->NumEntries() == 0) { + compact->current_output()->smallest.DecodeFrom(key); + } + compact->current_output()->largest.DecodeFrom(key); + compact->builder->Add(key, input->value()); + + // Close output file if it is big enough + if (compact->builder->FileSize() >= + compact->compaction->MaxOutputFileSize()) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + } + + input->Next(); + } + + if (status.ok() && shutting_down_.Acquire_Load()) { + status = Status::IOError("Deleting DB during compaction"); + } + if (status.ok() && compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + } + if (status.ok()) { + status = input->status(); + } + delete input; + input = NULL; + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros - imm_micros; + for (int which = 0; which < 2; which++) { + for (int i = 0; i < compact->compaction->num_input_files(which); i++) { + stats.bytes_read += compact->compaction->input(which, i)->file_size; + } + } + for (size_t i = 0; i < compact->outputs.size(); i++) { + stats.bytes_written += compact->outputs[i].file_size; + } + + mutex_.Lock(); + stats_[compact->compaction->level() + 1].Add(stats); + + if (status.ok()) { + status = InstallCompactionResults(compact); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, + "compacted to: %s", versions_->LevelSummary(&tmp)); + return status; +} + +namespace { +struct IterState { + port::Mutex* mu; + Version* version; + MemTable* mem; + MemTable* imm; +}; + +static void CleanupIteratorState(void* arg1, void* arg2) { + IterState* state = reinterpret_cast(arg1); + state->mu->Lock(); + state->mem->Unref(); + if (state->imm != NULL) state->imm->Unref(); + state->version->Unref(); + state->mu->Unlock(); + delete state; +} +} // namespace + +Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, + SequenceNumber* latest_snapshot) { + IterState* cleanup = new IterState; + mutex_.Lock(); + *latest_snapshot = versions_->LastSequence(); + + // Collect together all needed child iterators + std::vector list; + list.push_back(mem_->NewIterator()); + mem_->Ref(); + if (imm_ != NULL) { + list.push_back(imm_->NewIterator()); + imm_->Ref(); + } + versions_->current()->AddIterators(options, &list); + Iterator* internal_iter = + NewMergingIterator(&internal_comparator_, &list[0], list.size()); + versions_->current()->Ref(); + + cleanup->mu = &mutex_; + cleanup->mem = mem_; + cleanup->imm = imm_; + cleanup->version = versions_->current(); + internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); + + mutex_.Unlock(); + return internal_iter; +} + +Iterator* DBImpl::TEST_NewInternalIterator() { + SequenceNumber ignored; + return NewInternalIterator(ReadOptions(), &ignored); +} + +int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { + MutexLock l(&mutex_); + return versions_->MaxNextLevelOverlappingBytes(); +} + +Status DBImpl::Get(const ReadOptions& options, + const Slice& key, + std::string* value) { + Status s; + MutexLock l(&mutex_); + SequenceNumber snapshot; + if (options.snapshot != NULL) { + snapshot = reinterpret_cast(options.snapshot)->number_; + } else { + snapshot = versions_->LastSequence(); + } + + MemTable* mem = mem_; + MemTable* imm = imm_; + Version* current = versions_->current(); + mem->Ref(); + if (imm != NULL) imm->Ref(); + current->Ref(); + + bool have_stat_update = false; + Version::GetStats stats; + + // Unlock while reading from files and memtables + { + mutex_.Unlock(); + // First look in the memtable, then in the immutable memtable (if any). + LookupKey lkey(key, snapshot); + if (mem->Get(lkey, value, &s)) { + // Done + } else if (imm != NULL && imm->Get(lkey, value, &s)) { + // Done + } else { + s = current->Get(options, lkey, value, &stats); + have_stat_update = true; + } + mutex_.Lock(); + } + + if (have_stat_update && current->UpdateStats(stats)) { + MaybeScheduleCompaction(); + } + mem->Unref(); + if (imm != NULL) imm->Unref(); + current->Unref(); + return s; +} + +Iterator* DBImpl::NewIterator(const ReadOptions& options) { + SequenceNumber latest_snapshot; + Iterator* internal_iter = NewInternalIterator(options, &latest_snapshot); + return NewDBIterator( + &dbname_, env_, user_comparator(), internal_iter, + (options.snapshot != NULL + ? reinterpret_cast(options.snapshot)->number_ + : latest_snapshot)); +} + +const Snapshot* DBImpl::GetSnapshot() { + MutexLock l(&mutex_); + return snapshots_.New(versions_->LastSequence()); +} + +void DBImpl::ReleaseSnapshot(const Snapshot* s) { + MutexLock l(&mutex_); + snapshots_.Delete(reinterpret_cast(s)); +} + +// Convenience methods +Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { + return DB::Put(o, key, val); +} + +Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { + return DB::Delete(options, key); +} + +Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { + Writer w(&mutex_); + w.batch = my_batch; + w.sync = options.sync; + w.done = false; + + MutexLock l(&mutex_); + writers_.push_back(&w); + while (!w.done && &w != writers_.front()) { + w.cv.Wait(); + } + if (w.done) { + return w.status; + } + + // May temporarily unlock and wait. + Status status = MakeRoomForWrite(my_batch == NULL); + uint64_t last_sequence = versions_->LastSequence(); + Writer* last_writer = &w; + if (status.ok() && my_batch != NULL) { // NULL batch is for compactions + WriteBatch* updates = BuildBatchGroup(&last_writer); + WriteBatchInternal::SetSequence(updates, last_sequence + 1); + last_sequence += WriteBatchInternal::Count(updates); + + // Add to log and apply to memtable. We can release the lock + // during this phase since &w is currently responsible for logging + // and protects against concurrent loggers and concurrent writes + // into mem_. + { + mutex_.Unlock(); + status = log_->AddRecord(WriteBatchInternal::Contents(updates)); + if (status.ok() && options.sync) { + status = logfile_->Sync(); + } + if (status.ok()) { + status = WriteBatchInternal::InsertInto(updates, mem_); + } + mutex_.Lock(); + } + if (updates == tmp_batch_) tmp_batch_->Clear(); + + versions_->SetLastSequence(last_sequence); + } + + while (true) { + Writer* ready = writers_.front(); + writers_.pop_front(); + if (ready != &w) { + ready->status = status; + ready->done = true; + ready->cv.Signal(); + } + if (ready == last_writer) break; + } + + // Notify new head of write queue + if (!writers_.empty()) { + writers_.front()->cv.Signal(); + } + + return status; +} + +// REQUIRES: Writer list must be non-empty +// REQUIRES: First writer must have a non-NULL batch +WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { + assert(!writers_.empty()); + Writer* first = writers_.front(); + WriteBatch* result = first->batch; + assert(result != NULL); + + size_t size = WriteBatchInternal::ByteSize(first->batch); + + // Allow the group to grow up to a maximum size, but if the + // original write is small, limit the growth so we do not slow + // down the small write too much. + size_t max_size = 1 << 20; + if (size <= (128<<10)) { + max_size = size + (128<<10); + } + + *last_writer = first; + std::deque::iterator iter = writers_.begin(); + ++iter; // Advance past "first" + for (; iter != writers_.end(); ++iter) { + Writer* w = *iter; + if (w->sync && !first->sync) { + // Do not include a sync write into a batch handled by a non-sync write. + break; + } + + if (w->batch != NULL) { + size += WriteBatchInternal::ByteSize(w->batch); + if (size > max_size) { + // Do not make batch too big + break; + } + + // Append to *reuslt + if (result == first->batch) { + // Switch to temporary batch instead of disturbing caller's batch + result = tmp_batch_; + assert(WriteBatchInternal::Count(result) == 0); + WriteBatchInternal::Append(result, first->batch); + } + WriteBatchInternal::Append(result, w->batch); + } + *last_writer = w; + } + return result; +} + +// REQUIRES: mutex_ is held +// REQUIRES: this thread is currently at the front of the writer queue +Status DBImpl::MakeRoomForWrite(bool force) { + mutex_.AssertHeld(); + assert(!writers_.empty()); + bool allow_delay = !force; + Status s; + while (true) { + if (!bg_error_.ok()) { + // Yield previous error + s = bg_error_; + break; + } else if ( + allow_delay && + versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) { + // We are getting close to hitting a hard limit on the number of + // L0 files. Rather than delaying a single write by several + // seconds when we hit the hard limit, start delaying each + // individual write by 1ms to reduce latency variance. Also, + // this delay hands over some CPU to the compaction thread in + // case it is sharing the same core as the writer. + mutex_.Unlock(); + env_->SleepForMicroseconds(1000); + allow_delay = false; // Do not delay a single write more than once + mutex_.Lock(); + } else if (!force && + (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { + // There is room in current memtable + break; + } else if (imm_ != NULL) { + // We have filled up the current memtable, but the previous + // one is still being compacted, so we wait. + bg_cv_.Wait(); + } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { + // There are too many level-0 files. + Log(options_.info_log, "waiting...\n"); + bg_cv_.Wait(); + } else { + // Attempt to switch to a new memtable and trigger compaction of old + assert(versions_->PrevLogNumber() == 0); + uint64_t new_log_number = versions_->NewFileNumber(); + WritableFile* lfile = NULL; + s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); + if (!s.ok()) { + // Avoid chewing through file number space in a tight loop. + versions_->ReuseFileNumber(new_log_number); + break; + } + delete log_; + delete logfile_; + logfile_ = lfile; + logfile_number_ = new_log_number; + log_ = new log::Writer(lfile); + imm_ = mem_; + has_imm_.Release_Store(imm_); + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + force = false; // Do not force another compaction if have room + MaybeScheduleCompaction(); + } + } + return s; +} + +bool DBImpl::GetProperty(const Slice& property, std::string* value) { + value->clear(); + + MutexLock l(&mutex_); + Slice in = property; + Slice prefix("leveldb."); + if (!in.starts_with(prefix)) return false; + in.remove_prefix(prefix.size()); + + if (in.starts_with("num-files-at-level")) { + in.remove_prefix(strlen("num-files-at-level")); + uint64_t level; + bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); + if (!ok || level >= config::kNumLevels) { + return false; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "%d", + versions_->NumLevelFiles(static_cast(level))); + *value = buf; + return true; + } + } else if (in == "stats") { + char buf[200]; + snprintf(buf, sizeof(buf), + " Compactions\n" + "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" + "--------------------------------------------------\n" + ); + value->append(buf); + for (int level = 0; level < config::kNumLevels; level++) { + int files = versions_->NumLevelFiles(level); + if (stats_[level].micros > 0 || files > 0) { + snprintf( + buf, sizeof(buf), + "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", + level, + files, + versions_->NumLevelBytes(level) / 1048576.0, + stats_[level].micros / 1e6, + stats_[level].bytes_read / 1048576.0, + stats_[level].bytes_written / 1048576.0); + value->append(buf); + } + } + return true; + } else if (in == "sstables") { + *value = versions_->current()->DebugString(); + return true; + } + + return false; +} + +void DBImpl::GetApproximateSizes( + const Range* range, int n, + uint64_t* sizes) { + // TODO(opt): better implementation + Version* v; + { + MutexLock l(&mutex_); + versions_->current()->Ref(); + v = versions_->current(); + } + + for (int i = 0; i < n; i++) { + // Convert user_key into a corresponding internal key. + InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); + uint64_t start = versions_->ApproximateOffsetOf(v, k1); + uint64_t limit = versions_->ApproximateOffsetOf(v, k2); + sizes[i] = (limit >= start ? limit - start : 0); + } + + { + MutexLock l(&mutex_); + v->Unref(); + } +} + +// Default implementations of convenience methods that subclasses of DB +// can call if they wish +Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { + WriteBatch batch; + batch.Put(key, value); + return Write(opt, &batch); +} + +Status DB::Delete(const WriteOptions& opt, const Slice& key) { + WriteBatch batch; + batch.Delete(key); + return Write(opt, &batch); +} + +DB::~DB() { } + +Status DB::Open(const Options& options, const std::string& dbname, + DB** dbptr) { + *dbptr = NULL; + + DBImpl* impl = new DBImpl(options, dbname); + impl->mutex_.Lock(); + VersionEdit edit; + Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists + if (s.ok()) { + uint64_t new_log_number = impl->versions_->NewFileNumber(); + WritableFile* lfile; + s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), + &lfile); + if (s.ok()) { + edit.SetLogNumber(new_log_number); + impl->logfile_ = lfile; + impl->logfile_number_ = new_log_number; + impl->log_ = new log::Writer(lfile); + s = impl->versions_->LogAndApply(&edit, &impl->mutex_); + } + if (s.ok()) { + impl->DeleteObsoleteFiles(); + impl->MaybeScheduleCompaction(); + } + } + impl->mutex_.Unlock(); + if (s.ok()) { + *dbptr = impl; + } else { + delete impl; + } + return s; +} + +Snapshot::~Snapshot() { +} + +Status DestroyDB(const std::string& dbname, const Options& options) { + Env* env = options.env; + std::vector filenames; + // Ignore error in case directory does not exist + env->GetChildren(dbname, &filenames); + if (filenames.empty()) { + return Status::OK(); + } + + FileLock* lock; + const std::string lockname = LockFileName(dbname); + Status result = env->LockFile(lockname, &lock); + if (result.ok()) { + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type != kDBLockFile) { // Lock file will be deleted at end + Status del = env->DeleteFile(dbname + "/" + filenames[i]); + if (result.ok() && !del.ok()) { + result = del; + } + } + } + env->UnlockFile(lock); // Ignore error since state is already gone + env->DeleteFile(lockname); + env->DeleteDir(dbname); // Ignore error in case dir contains other files + } + return result; +} + +} // namespace leveldb diff --git a/db/db_impl.h b/db/db_impl.h new file mode 100644 index 000000000..bd29dd805 --- /dev/null +++ b/db/db_impl.h @@ -0,0 +1,202 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_ +#define STORAGE_LEVELDB_DB_DB_IMPL_H_ + +#include +#include +#include "db/dbformat.h" +#include "db/log_writer.h" +#include "db/snapshot.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +class MemTable; +class TableCache; +class Version; +class VersionEdit; +class VersionSet; + +class DBImpl : public DB { + public: + DBImpl(const Options& options, const std::string& dbname); + virtual ~DBImpl(); + + // Implementations of the DB interface + virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); + virtual Status Delete(const WriteOptions&, const Slice& key); + virtual Status Write(const WriteOptions& options, WriteBatch* updates); + virtual Status Get(const ReadOptions& options, + const Slice& key, + std::string* value); + virtual Iterator* NewIterator(const ReadOptions&); + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); + virtual void CompactRange(const Slice* begin, const Slice* end); + + // Extra methods (for testing) that are not in the public DB interface + + // Compact any files in the named level that overlap [*begin,*end] + void TEST_CompactRange(int level, const Slice* begin, const Slice* end); + + // Force current memtable contents to be compacted. + Status TEST_CompactMemTable(); + + // Return an internal iterator over the current state of the database. + // The keys of this iterator are internal keys (see format.h). + // The returned iterator should be deleted when no longer needed. + Iterator* TEST_NewInternalIterator(); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t TEST_MaxNextLevelOverlappingBytes(); + + private: + friend class DB; + struct CompactionState; + struct Writer; + + Iterator* NewInternalIterator(const ReadOptions&, + SequenceNumber* latest_snapshot); + + Status NewDB(); + + // Recover the descriptor from persistent storage. May do a significant + // amount of work to recover recently logged updates. Any changes to + // be made to the descriptor are added to *edit. + Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void MaybeIgnoreError(Status* s) const; + + // Delete any unneeded files and stale in-memory entries. + void DeleteObsoleteFiles(); + + // Compact the in-memory write buffer to disk. Switches to a new + // log-file/memtable and writes a new descriptor iff successful. + Status CompactMemTable() + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status RecoverLogFile(uint64_t log_number, + VersionEdit* edit, + SequenceNumber* max_sequence) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status MakeRoomForWrite(bool force /* compact even if there is room? */) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + WriteBatch* BuildBatchGroup(Writer** last_writer); + + void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + static void BGWork(void* db); + void BackgroundCall(); + Status BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void CleanupCompaction(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Status DoCompactionWork(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status OpenCompactionOutputFile(CompactionState* compact); + Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); + Status InstallCompactionResults(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Constant after construction + Env* const env_; + const InternalKeyComparator internal_comparator_; + const InternalFilterPolicy internal_filter_policy_; + const Options options_; // options_.comparator == &internal_comparator_ + bool owns_info_log_; + bool owns_cache_; + const std::string dbname_; + + // table_cache_ provides its own synchronization + TableCache* table_cache_; + + // Lock over the persistent DB state. Non-NULL iff successfully acquired. + FileLock* db_lock_; + + // State below is protected by mutex_ + port::Mutex mutex_; + port::AtomicPointer shutting_down_; + port::CondVar bg_cv_; // Signalled when background work finishes + MemTable* mem_; + MemTable* imm_; // Memtable being compacted + port::AtomicPointer has_imm_; // So bg thread can detect non-NULL imm_ + WritableFile* logfile_; + uint64_t logfile_number_; + log::Writer* log_; + + // Queue of writers. + std::deque writers_; + WriteBatch* tmp_batch_; + + SnapshotList snapshots_; + + // Set of table files to protect from deletion because they are + // part of ongoing compactions. + std::set pending_outputs_; + + // Has a background compaction been scheduled or is running? + bool bg_compaction_scheduled_; + + // Information for a manual compaction + struct ManualCompaction { + int level; + bool done; + const InternalKey* begin; // NULL means beginning of key range + const InternalKey* end; // NULL means end of key range + InternalKey tmp_storage; // Used to keep track of compaction progress + }; + ManualCompaction* manual_compaction_; + + VersionSet* versions_; + + // Have we encountered a background error in paranoid mode? + Status bg_error_; + + // Per level compaction stats. stats_[level] stores the stats for + // compactions that produced data for the specified "level". + struct CompactionStats { + int64_t micros; + int64_t bytes_read; + int64_t bytes_written; + + CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { } + + void Add(const CompactionStats& c) { + this->micros += c.micros; + this->bytes_read += c.bytes_read; + this->bytes_written += c.bytes_written; + } + }; + CompactionStats stats_[config::kNumLevels]; + + // No copying allowed + DBImpl(const DBImpl&); + void operator=(const DBImpl&); + + const Comparator* user_comparator() const { + return internal_comparator_.user_comparator(); + } +}; + +// Sanitize db options. The caller should delete result.info_log if +// it is not equal to src.info_log. +extern Options SanitizeOptions(const std::string& db, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/db/db_iter.cc b/db/db_iter.cc new file mode 100644 index 000000000..87dca2ded --- /dev/null +++ b/db/db_iter.cc @@ -0,0 +1,299 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_iter.h" + +#include "db/filename.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" + +namespace leveldb { + +#if 0 +static void DumpInternalIter(Iterator* iter) { + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey k; + if (!ParseInternalKey(iter->key(), &k)) { + fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); + } else { + fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); + } + } +} +#endif + +namespace { + +// Memtables and sstables that make the DB representation contain +// (userkey,seq,type) => uservalue entries. DBIter +// combines multiple entries for the same userkey found in the DB +// representation into a single entry while accounting for sequence +// numbers, deletion markers, overwrites, etc. +class DBIter: public Iterator { + public: + // Which direction is the iterator currently moving? + // (1) When moving forward, the internal iterator is positioned at + // the exact entry that yields this->key(), this->value() + // (2) When moving backwards, the internal iterator is positioned + // just before all entries whose user key == this->key(). + enum Direction { + kForward, + kReverse + }; + + DBIter(const std::string* dbname, Env* env, + const Comparator* cmp, Iterator* iter, SequenceNumber s) + : dbname_(dbname), + env_(env), + user_comparator_(cmp), + iter_(iter), + sequence_(s), + direction_(kForward), + valid_(false) { + } + virtual ~DBIter() { + delete iter_; + } + virtual bool Valid() const { return valid_; } + virtual Slice key() const { + assert(valid_); + return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; + } + virtual Slice value() const { + assert(valid_); + return (direction_ == kForward) ? iter_->value() : saved_value_; + } + virtual Status status() const { + if (status_.ok()) { + return iter_->status(); + } else { + return status_; + } + } + + virtual void Next(); + virtual void Prev(); + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + + private: + void FindNextUserEntry(bool skipping, std::string* skip); + void FindPrevUserEntry(); + bool ParseKey(ParsedInternalKey* key); + + inline void SaveKey(const Slice& k, std::string* dst) { + dst->assign(k.data(), k.size()); + } + + inline void ClearSavedValue() { + if (saved_value_.capacity() > 1048576) { + std::string empty; + swap(empty, saved_value_); + } else { + saved_value_.clear(); + } + } + + const std::string* const dbname_; + Env* const env_; + const Comparator* const user_comparator_; + Iterator* const iter_; + SequenceNumber const sequence_; + + Status status_; + std::string saved_key_; // == current key when direction_==kReverse + std::string saved_value_; // == current raw value when direction_==kReverse + Direction direction_; + bool valid_; + + // No copying allowed + DBIter(const DBIter&); + void operator=(const DBIter&); +}; + +inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { + if (!ParseInternalKey(iter_->key(), ikey)) { + status_ = Status::Corruption("corrupted internal key in DBIter"); + return false; + } else { + return true; + } +} + +void DBIter::Next() { + assert(valid_); + + if (direction_ == kReverse) { // Switch directions? + direction_ = kForward; + // iter_ is pointing just before the entries for this->key(), + // so advance into the range of entries for this->key() and then + // use the normal skipping code below. + if (!iter_->Valid()) { + iter_->SeekToFirst(); + } else { + iter_->Next(); + } + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + return; + } + } + + // Temporarily use saved_key_ as storage for key to skip. + std::string* skip = &saved_key_; + SaveKey(ExtractUserKey(iter_->key()), skip); + FindNextUserEntry(true, skip); +} + +void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { + // Loop until we hit an acceptable entry to yield + assert(iter_->Valid()); + assert(direction_ == kForward); + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + switch (ikey.type) { + case kTypeDeletion: + // Arrange to skip all upcoming entries for this key since + // they are hidden by this deletion. + SaveKey(ikey.user_key, skip); + skipping = true; + break; + case kTypeValue: + if (skipping && + user_comparator_->Compare(ikey.user_key, *skip) <= 0) { + // Entry hidden + } else { + valid_ = true; + saved_key_.clear(); + return; + } + break; + } + } + iter_->Next(); + } while (iter_->Valid()); + saved_key_.clear(); + valid_ = false; +} + +void DBIter::Prev() { + assert(valid_); + + if (direction_ == kForward) { // Switch directions? + // iter_ is pointing at the current entry. Scan backwards until + // the key changes so we can use the normal reverse scanning code. + assert(iter_->Valid()); // Otherwise valid_ would have been false + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + while (true) { + iter_->Prev(); + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + return; + } + if (user_comparator_->Compare(ExtractUserKey(iter_->key()), + saved_key_) < 0) { + break; + } + } + direction_ = kReverse; + } + + FindPrevUserEntry(); +} + +void DBIter::FindPrevUserEntry() { + assert(direction_ == kReverse); + + ValueType value_type = kTypeDeletion; + if (iter_->Valid()) { + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + if ((value_type != kTypeDeletion) && + user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { + // We encountered a non-deleted value in entries for previous keys, + break; + } + value_type = ikey.type; + if (value_type == kTypeDeletion) { + saved_key_.clear(); + ClearSavedValue(); + } else { + Slice raw_value = iter_->value(); + if (saved_value_.capacity() > raw_value.size() + 1048576) { + std::string empty; + swap(empty, saved_value_); + } + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + saved_value_.assign(raw_value.data(), raw_value.size()); + } + } + iter_->Prev(); + } while (iter_->Valid()); + } + + if (value_type == kTypeDeletion) { + // End + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + direction_ = kForward; + } else { + valid_ = true; + } +} + +void DBIter::Seek(const Slice& target) { + direction_ = kForward; + ClearSavedValue(); + saved_key_.clear(); + AppendInternalKey( + &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek)); + iter_->Seek(saved_key_); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToFirst() { + direction_ = kForward; + ClearSavedValue(); + iter_->SeekToFirst(); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToLast() { + direction_ = kReverse; + ClearSavedValue(); + iter_->SeekToLast(); + FindPrevUserEntry(); +} + +} // anonymous namespace + +Iterator* NewDBIterator( + const std::string* dbname, + Env* env, + const Comparator* user_key_comparator, + Iterator* internal_iter, + const SequenceNumber& sequence) { + return new DBIter(dbname, env, user_key_comparator, internal_iter, sequence); +} + +} // namespace leveldb diff --git a/db/db_iter.h b/db/db_iter.h new file mode 100644 index 000000000..d9e1b174a --- /dev/null +++ b/db/db_iter.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_ +#define STORAGE_LEVELDB_DB_DB_ITER_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" + +namespace leveldb { + +// Return a new iterator that converts internal keys (yielded by +// "*internal_iter") that were live at the specified "sequence" number +// into appropriate user keys. +extern Iterator* NewDBIterator( + const std::string* dbname, + Env* env, + const Comparator* user_key_comparator, + Iterator* internal_iter, + const SequenceNumber& sequence); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/db/db_test.cc b/db/db_test.cc new file mode 100644 index 000000000..684ea3bdb --- /dev/null +++ b/db/db_test.cc @@ -0,0 +1,2027 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static std::string RandomString(Random* rnd, int len) { + std::string r; + test::RandomString(rnd, len, &r); + return r; +} + +namespace { +class AtomicCounter { + private: + port::Mutex mu_; + int count_; + public: + AtomicCounter() : count_(0) { } + void Increment() { + MutexLock l(&mu_); + count_++; + } + int Read() { + MutexLock l(&mu_); + return count_; + } + void Reset() { + MutexLock l(&mu_); + count_ = 0; + } +}; +} + +// Special Env used to delay background operations +class SpecialEnv : public EnvWrapper { + public: + // sstable Sync() calls are blocked while this pointer is non-NULL. + port::AtomicPointer delay_sstable_sync_; + + // Simulate no-space errors while this pointer is non-NULL. + port::AtomicPointer no_space_; + + // Simulate non-writable file system while this pointer is non-NULL + port::AtomicPointer non_writable_; + + // Force sync of manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_sync_error_; + + // Force write to manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_write_error_; + + bool count_random_reads_; + AtomicCounter random_read_counter_; + + AtomicCounter sleep_counter_; + + explicit SpecialEnv(Env* base) : EnvWrapper(base) { + delay_sstable_sync_.Release_Store(NULL); + no_space_.Release_Store(NULL); + non_writable_.Release_Store(NULL); + count_random_reads_ = false; + manifest_sync_error_.Release_Store(NULL); + manifest_write_error_.Release_Store(NULL); + } + + Status NewWritableFile(const std::string& f, WritableFile** r) { + class SSTableFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + + public: + SSTableFile(SpecialEnv* env, WritableFile* base) + : env_(env), + base_(base) { + } + ~SSTableFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->no_space_.Acquire_Load() != NULL) { + // Drop writes on the floor + return Status::OK(); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + while (env_->delay_sstable_sync_.Acquire_Load() != NULL) { + env_->SleepForMicroseconds(100000); + } + return base_->Sync(); + } + }; + class ManifestFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + public: + ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { } + ~ManifestFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->manifest_write_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated writer error"); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + if (env_->manifest_sync_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated sync error"); + } else { + return base_->Sync(); + } + } + }; + + if (non_writable_.Acquire_Load() != NULL) { + return Status::IOError("simulated write error"); + } + + Status s = target()->NewWritableFile(f, r); + if (s.ok()) { + if (strstr(f.c_str(), ".sst") != NULL) { + *r = new SSTableFile(this, *r); + } else if (strstr(f.c_str(), "MANIFEST") != NULL) { + *r = new ManifestFile(this, *r); + } + } + return s; + } + + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + class CountingFile : public RandomAccessFile { + private: + RandomAccessFile* target_; + AtomicCounter* counter_; + public: + CountingFile(RandomAccessFile* target, AtomicCounter* counter) + : target_(target), counter_(counter) { + } + virtual ~CountingFile() { delete target_; } + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + counter_->Increment(); + return target_->Read(offset, n, result, scratch); + } + }; + + Status s = target()->NewRandomAccessFile(f, r); + if (s.ok() && count_random_reads_) { + *r = new CountingFile(*r, &random_read_counter_); + } + return s; + } + + virtual void SleepForMicroseconds(int micros) { + sleep_counter_.Increment(); + target()->SleepForMicroseconds(micros); + } +}; + +class DBTest { + private: + const FilterPolicy* filter_policy_; + + // Sequence of option configurations to try + enum OptionConfig { + kDefault, + kFilter, + kUncompressed, + kEnd + }; + int option_config_; + + public: + std::string dbname_; + SpecialEnv* env_; + DB* db_; + + Options last_options_; + + DBTest() : option_config_(kDefault), + env_(new SpecialEnv(Env::Default())) { + filter_policy_ = NewBloomFilterPolicy(10); + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, Options()); + db_ = NULL; + Reopen(); + } + + ~DBTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete env_; + delete filter_policy_; + } + + // Switch to a fresh database with the next option configuration to + // test. Return false if there are no more configurations to test. + bool ChangeOptions() { + option_config_++; + if (option_config_ >= kEnd) { + return false; + } else { + DestroyAndReopen(); + return true; + } + } + + // Return the current option configuration. + Options CurrentOptions() { + Options options; + switch (option_config_) { + case kFilter: + options.filter_policy = filter_policy_; + break; + case kUncompressed: + options.compression = kNoCompression; + break; + default: + break; + } + return options; + } + + DBImpl* dbfull() { + return reinterpret_cast(db_); + } + + void Reopen(Options* options = NULL) { + ASSERT_OK(TryReopen(options)); + } + + void Close() { + delete db_; + db_ = NULL; + } + + void DestroyAndReopen(Options* options = NULL) { + delete db_; + db_ = NULL; + DestroyDB(dbname_, Options()); + ASSERT_OK(TryReopen(options)); + } + + Status TryReopen(Options* options) { + delete db_; + db_ = NULL; + Options opts; + if (options != NULL) { + opts = *options; + } else { + opts = CurrentOptions(); + opts.create_if_missing = true; + } + last_options_ = opts; + + return DB::Open(opts, dbname_, &db_); + } + + Status Put(const std::string& k, const std::string& v) { + return db_->Put(WriteOptions(), k, v); + } + + Status Delete(const std::string& k) { + return db_->Delete(WriteOptions(), k); + } + + std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { + ReadOptions options; + options.snapshot = snapshot; + std::string result; + Status s = db_->Get(options, k, &result); + if (s.IsNotFound()) { + result = "NOT_FOUND"; + } else if (!s.ok()) { + result = s.ToString(); + } + return result; + } + + // Return a string that contains all key,value pairs in order, + // formatted like "(k1->v1)(k2->v2)". + std::string Contents() { + std::vector forward; + std::string result; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + std::string s = IterStatus(iter); + result.push_back('('); + result.append(s); + result.push_back(')'); + forward.push_back(s); + } + + // Check reverse iteration results are the reverse of forward results + int matched = 0; + for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { + ASSERT_LT(matched, forward.size()); + ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]); + matched++; + } + ASSERT_EQ(matched, forward.size()); + + delete iter; + return result; + } + + std::string AllEntriesFor(const Slice& user_key) { + Iterator* iter = dbfull()->TEST_NewInternalIterator(); + InternalKey target(user_key, kMaxSequenceNumber, kTypeValue); + iter->Seek(target.Encode()); + std::string result; + if (!iter->status().ok()) { + result = iter->status().ToString(); + } else { + result = "[ "; + bool first = true; + while (iter->Valid()) { + ParsedInternalKey ikey; + if (!ParseInternalKey(iter->key(), &ikey)) { + result += "CORRUPTED"; + } else { + if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) { + break; + } + if (!first) { + result += ", "; + } + first = false; + switch (ikey.type) { + case kTypeValue: + result += iter->value().ToString(); + break; + case kTypeDeletion: + result += "DEL"; + break; + } + } + iter->Next(); + } + if (!first) { + result += " "; + } + result += "]"; + } + delete iter; + return result; + } + + int NumTableFilesAtLevel(int level) { + std::string property; + ASSERT_TRUE( + db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level), + &property)); + return atoi(property.c_str()); + } + + int TotalTableFiles() { + int result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + result += NumTableFilesAtLevel(level); + } + return result; + } + + // Return spread of files per level + std::string FilesPerLevel() { + std::string result; + int last_non_zero_offset = 0; + for (int level = 0; level < config::kNumLevels; level++) { + int f = NumTableFilesAtLevel(level); + char buf[100]; + snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f); + result += buf; + if (f > 0) { + last_non_zero_offset = result.size(); + } + } + result.resize(last_non_zero_offset); + return result; + } + + int CountFiles() { + std::vector files; + env_->GetChildren(dbname_, &files); + return static_cast(files.size()); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void Compact(const Slice& start, const Slice& limit) { + db_->CompactRange(&start, &limit); + } + + // Do n memtable compactions, each of which produces an sstable + // covering the range [small,large]. + void MakeTables(int n, const std::string& small, const std::string& large) { + for (int i = 0; i < n; i++) { + Put(small, "begin"); + Put(large, "end"); + dbfull()->TEST_CompactMemTable(); + } + } + + // Prevent pushing of new sstables into deeper levels by adding + // tables that cover a specified range to all levels. + void FillLevels(const std::string& smallest, const std::string& largest) { + MakeTables(config::kNumLevels, smallest, largest); + } + + void DumpFileCounts(const char* label) { + fprintf(stderr, "---\n%s:\n", label); + fprintf(stderr, "maxoverlap: %lld\n", + static_cast( + dbfull()->TEST_MaxNextLevelOverlappingBytes())); + for (int level = 0; level < config::kNumLevels; level++) { + int num = NumTableFilesAtLevel(level); + if (num > 0) { + fprintf(stderr, " level %3d : %d files\n", level, num); + } + } + } + + std::string DumpSSTableList() { + std::string property; + db_->GetProperty("leveldb.sstables", &property); + return property; + } + + std::string IterStatus(Iterator* iter) { + std::string result; + if (iter->Valid()) { + result = iter->key().ToString() + "->" + iter->value().ToString(); + } else { + result = "(invalid)"; + } + return result; + } +}; + +TEST(DBTest, Empty) { + do { + ASSERT_TRUE(db_ != NULL); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, ReadWrite) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + ASSERT_EQ("v3", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + } while (ChangeOptions()); +} + +TEST(DBTest, PutDeleteGet) { + do { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + ASSERT_OK(db_->Delete(WriteOptions(), "foo")); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromImmutableLayer) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + + env_->delay_sstable_sync_.Release_Store(env_); // Block sync calls + Put("k1", std::string(100000, 'x')); // Fill memtable + Put("k2", std::string(100000, 'y')); // Trigger compaction + ASSERT_EQ("v1", Get("foo")); + env_->delay_sstable_sync_.Release_Store(NULL); // Release sync calls + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromVersions) { + do { + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v1", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetSnapshot) { + do { + // Try with both a short key and a long key + for (int i = 0; i < 2; i++) { + std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x'); + ASSERT_OK(Put(key, "v1")); + const Snapshot* s1 = db_->GetSnapshot(); + ASSERT_OK(Put(key, "v2")); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + db_->ReleaseSnapshot(s1); + } + } while (ChangeOptions()); +} + +TEST(DBTest, GetLevel0Ordering) { + do { + // Check that we process level-0 files in correct order. The code + // below generates two level-0 files where the earlier one comes + // before the later one in the level-0 file list since the earlier + // one has a smaller "smallest" key. + ASSERT_OK(Put("bar", "b")); + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("foo", "v2")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetOrderedByLevels) { + do { + ASSERT_OK(Put("foo", "v1")); + Compact("a", "z"); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetPicksCorrectFile) { + do { + // Arrange to have multiple files in a non-level-0 level. + ASSERT_OK(Put("a", "va")); + Compact("a", "b"); + ASSERT_OK(Put("x", "vx")); + Compact("x", "y"); + ASSERT_OK(Put("f", "vf")); + Compact("f", "g"); + ASSERT_EQ("va", Get("a")); + ASSERT_EQ("vf", Get("f")); + ASSERT_EQ("vx", Get("x")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetEncountersEmptyLevel) { + do { + // Arrange for the following to happen: + // * sstable A in level 0 + // * nothing in level 1 + // * sstable B in level 2 + // Then do enough Get() calls to arrange for an automatic compaction + // of sstable A. A bug would cause the compaction to be marked as + // occuring at level 1 (instead of the correct level 0). + + // Step 1: First place sstables in levels 0 and 2 + int compaction_count = 0; + while (NumTableFilesAtLevel(0) == 0 || + NumTableFilesAtLevel(2) == 0) { + ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2"; + compaction_count++; + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + } + + // Step 2: clear level 1 if necessary. + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_EQ(NumTableFilesAtLevel(0), 1); + ASSERT_EQ(NumTableFilesAtLevel(1), 0); + ASSERT_EQ(NumTableFilesAtLevel(2), 1); + + // Step 3: read a bunch of times + for (int i = 0; i < 1000; i++) { + ASSERT_EQ("NOT_FOUND", Get("missing")); + } + + // Step 4: Wait for compaction to finish + env_->SleepForMicroseconds(1000000); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } while (ChangeOptions()); +} + +TEST(DBTest, IterEmpty) { + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("foo"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSingle) { + ASSERT_OK(Put("a", "va")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMulti) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("ax"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("z"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + // Switch from reverse to forward + iter->SeekToLast(); + iter->Prev(); + iter->Prev(); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Switch from forward to reverse + iter->SeekToFirst(); + iter->Next(); + iter->Next(); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Make sure iter stays at snapshot + ASSERT_OK(Put("a", "va2")); + ASSERT_OK(Put("a2", "va3")); + ASSERT_OK(Put("b", "vb2")); + ASSERT_OK(Put("c", "vc2")); + ASSERT_OK(Delete("b")); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSmallAndLargeMix) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", std::string(100000, 'b'))); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Put("d", std::string(100000, 'd'))); + ASSERT_OK(Put("e", std::string(100000, 'e'))); + + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMultiWithDelete) { + do { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Delete("b")); + ASSERT_EQ("NOT_FOUND", Get("b")); + + Iterator* iter = db_->NewIterator(ReadOptions()); + iter->Seek("c"); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + delete iter; + } while (ChangeOptions()); +} + +TEST(DBTest, Recover) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("baz", "v5")); + + Reopen(); + ASSERT_EQ("v1", Get("foo")); + + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v5", Get("baz")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + + Reopen(); + ASSERT_EQ("v3", Get("foo")); + ASSERT_OK(Put("foo", "v4")); + ASSERT_EQ("v4", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ("v5", Get("baz")); + } while (ChangeOptions()); +} + +TEST(DBTest, RecoveryWithEmptyLog) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("foo", "v2")); + Reopen(); + Reopen(); + ASSERT_OK(Put("foo", "v3")); + Reopen(); + ASSERT_EQ("v3", Get("foo")); + } while (ChangeOptions()); +} + +// Check that writes done during a memtable compaction are recovered +// if the database is shutdown during the memtable compaction. +TEST(DBTest, RecoverDuringMemtableCompaction) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 1000000; + Reopen(&options); + + // Trigger a long memtable compaction and reopen the database during it + ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file + ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable + ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction + ASSERT_OK(Put("bar", "v2")); // Goes to new log file + + Reopen(&options); + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ(std::string(10000000, 'x'), Get("big1")); + ASSERT_EQ(std::string(1000, 'y'), Get("big2")); + } while (ChangeOptions()); +} + +static std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); +} + +TEST(DBTest, MinorCompactionsHappen) { + Options options = CurrentOptions(); + options.write_buffer_size = 10000; + Reopen(&options); + + const int N = 500; + + int starting_num_tables = TotalTableFiles(); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v'))); + } + int ending_num_tables = TotalTableFiles(); + ASSERT_GT(ending_num_tables, starting_num_tables); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } + + Reopen(); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } +} + +TEST(DBTest, RecoverWithLargeLog) { + { + Options options = CurrentOptions(); + Reopen(&options); + ASSERT_OK(Put("big1", std::string(200000, '1'))); + ASSERT_OK(Put("big2", std::string(200000, '2'))); + ASSERT_OK(Put("small3", std::string(10, '3'))); + ASSERT_OK(Put("small4", std::string(10, '4'))); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } + + // Make sure that if we re-open with a small write buffer size that + // we flush table files in the middle of a large log file. + Options options = CurrentOptions(); + options.write_buffer_size = 100000; + Reopen(&options); + ASSERT_EQ(NumTableFilesAtLevel(0), 3); + ASSERT_EQ(std::string(200000, '1'), Get("big1")); + ASSERT_EQ(std::string(200000, '2'), Get("big2")); + ASSERT_EQ(std::string(10, '3'), Get("small3")); + ASSERT_EQ(std::string(10, '4'), Get("small4")); + ASSERT_GT(NumTableFilesAtLevel(0), 1); +} + +TEST(DBTest, CompactionsGenerateMultipleFiles) { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + Reopen(&options); + + Random rnd(301); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + std::vector values; + for (int i = 0; i < 80; i++) { + values.push_back(RandomString(&rnd, 100000)); + ASSERT_OK(Put(Key(i), values[i])); + } + + // Reopening moves updates to level-0 + Reopen(&options); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 1); + for (int i = 0; i < 80; i++) { + ASSERT_EQ(Get(Key(i)), values[i]); + } +} + +TEST(DBTest, RepeatedWritesToSameKey) { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + // We must have at most one file per level except for level-0, + // which may have up to kL0_StopWritesTrigger files. + const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger; + + Random rnd(301); + std::string value = RandomString(&rnd, 2 * options.write_buffer_size); + for (int i = 0; i < 5 * kMaxFiles; i++) { + Put("key", value); + ASSERT_LE(TotalTableFiles(), kMaxFiles); + fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles()); + } +} + +TEST(DBTest, SparseMerge) { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(&options); + + FillLevels("A", "Z"); + + // Suppose there is: + // small amount of data with prefix A + // large amount of data with prefix B + // small amount of data with prefix C + // and that recent updates have made small changes to all three prefixes. + // Check that we do not do a compaction that merges all of B in one shot. + const std::string value(1000, 'x'); + Put("A", "va"); + // Write approximately 100MB of "B" values + for (int i = 0; i < 100000; i++) { + char key[100]; + snprintf(key, sizeof(key), "B%010d", i); + Put(key, value); + } + Put("C", "vc"); + dbfull()->TEST_CompactMemTable(); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + // Make sparse update + Put("A", "va2"); + Put("B100", "bvalue2"); + Put("C", "vc2"); + dbfull()->TEST_CompactMemTable(); + + // Compactions should not cause us to create a situation where + // a file overlaps too much data at the next level. + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(0, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +TEST(DBTest, ApproximateSizes) { + do { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + options.compression = kNoCompression; + DestroyAndReopen(); + + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + Reopen(&options); + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + const int N = 80; + static const int S1 = 100000; + static const int S2 = 105000; // Allow some expansion from metadata + Random rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), RandomString(&rnd, S1))); + } + + // 0 because GetApproximateSizes() does not account for memtable space + ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + for (int compact_start = 0; compact_start < N; compact_start += 10) { + for (int i = 0; i < N; i += 10) { + ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i)); + ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1))); + ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10)); + } + ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50)); + ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50)); + + std::string cstart_str = Key(compact_start); + std::string cend_str = Key(compact_start + 9); + Slice cstart = cstart_str; + Slice cend = cend_str; + dbfull()->TEST_CompactRange(0, &cstart, &cend); + } + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 0); + } + } while (ChangeOptions()); +} + +TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { + do { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(); + + Random rnd(301); + std::string big1 = RandomString(&rnd, 100000); + ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(2), big1)); + ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(4), big1)); + ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); + ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + ASSERT_TRUE(Between(Size("", Key(0)), 0, 0)); + ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000)); + ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000)); + ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000)); + ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000)); + ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000)); + ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000)); + ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000)); + ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000)); + + ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000)); + + dbfull()->TEST_CompactRange(0, NULL, NULL); + } + } while (ChangeOptions()); +} + +TEST(DBTest, IteratorPinsRef) { + Put("foo", "hello"); + + // Get iterator that will yield the current contents of the DB. + Iterator* iter = db_->NewIterator(ReadOptions()); + + // Write to force compactions + Put("foo", "newvalue1"); + for (int i = 0; i < 100; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values + } + Put("foo", "newvalue2"); + + iter->SeekToFirst(); + ASSERT_TRUE(iter->Valid()); + ASSERT_EQ("foo", iter->key().ToString()); + ASSERT_EQ("hello", iter->value().ToString()); + iter->Next(); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +TEST(DBTest, Snapshot) { + do { + Put("foo", "v1"); + const Snapshot* s1 = db_->GetSnapshot(); + Put("foo", "v2"); + const Snapshot* s2 = db_->GetSnapshot(); + Put("foo", "v3"); + const Snapshot* s3 = db_->GetSnapshot(); + + Put("foo", "v4"); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v3", Get("foo", s3)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s3); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s1); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s2); + ASSERT_EQ("v4", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, HiddenValuesAreRemoved) { + do { + Random rnd(301); + FillLevels("a", "z"); + + std::string big = RandomString(&rnd, 50000); + Put("foo", big); + Put("pastfoo", "v"); + const Snapshot* snapshot = db_->GetSnapshot(); + Put("foo", "tiny"); + Put("pastfoo2", "v2"); // Advance sequence number one more + + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + ASSERT_GT(NumTableFilesAtLevel(0), 0); + + ASSERT_EQ(big, Get("foo", snapshot)); + ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000)); + db_->ReleaseSnapshot(snapshot); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]"); + Slice x("x"); + dbfull()->TEST_CompactRange(0, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GE(NumTableFilesAtLevel(1), 1); + dbfull()->TEST_CompactRange(1, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + + ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000)); + } while (ChangeOptions()); +} + +TEST(DBTest, DeletionMarkers1) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + Put("foo", "v2"); + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + Slice z("z"); + dbfull()->TEST_CompactRange(last-2, NULL, &z); + // DEL eliminated, but v1 remains because we aren't compacting that level + // (DEL can be eliminated because v2 hides v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]"); +} + +TEST(DBTest, DeletionMarkers2) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-2, NULL, NULL); + // DEL kept: "last" file overlaps + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ ]"); +} + +TEST(DBTest, OverlapInLevel0) { + do { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config"; + + // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. + ASSERT_OK(Put("100", "v100")); + ASSERT_OK(Put("999", "v999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Delete("100")); + ASSERT_OK(Delete("999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("0,1,1", FilesPerLevel()); + + // Make files spanning the following ranges in level-0: + // files[0] 200 .. 900 + // files[1] 300 .. 500 + // Note that files are sorted by smallest key. + ASSERT_OK(Put("300", "v300")); + ASSERT_OK(Put("500", "v500")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("200", "v200")); + ASSERT_OK(Put("600", "v600")); + ASSERT_OK(Put("900", "v900")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("2,1,1", FilesPerLevel()); + + // Compact away the placeholder files we created initially + dbfull()->TEST_CompactRange(1, NULL, NULL); + dbfull()->TEST_CompactRange(2, NULL, NULL); + ASSERT_EQ("2", FilesPerLevel()); + + // Do a memtable compaction. Before bug-fix, the compaction would + // not detect the overlap with level-0 files and would incorrectly place + // the deletion in a deeper level. + ASSERT_OK(Delete("600")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("3", FilesPerLevel()); + ASSERT_EQ("NOT_FOUND", Get("600")); + } while (ChangeOptions()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_a) { + Reopen(); + ASSERT_OK(Put("b", "v")); + Reopen(); + ASSERT_OK(Delete("b")); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Put("a", "v")); + Reopen(); + Reopen(); + ASSERT_EQ("(a->v)", Contents()); + env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + ASSERT_EQ("(a->v)", Contents()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_b) { + Reopen(); + Put("",""); + Reopen(); + Delete("e"); + Put("",""); + Reopen(); + Put("c", "cv"); + Reopen(); + Put("",""); + Reopen(); + Put("",""); + env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + Reopen(); + Put("d","dv"); + Reopen(); + Put("",""); + Reopen(); + Delete("d"); + Delete("b"); + Reopen(); + ASSERT_EQ("(->)(c->cv)", Contents()); + env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + ASSERT_EQ("(->)(c->cv)", Contents()); +} + +TEST(DBTest, ComparatorCheck) { + class NewComparator : public Comparator { + public: + virtual const char* Name() const { return "leveldb.NewComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(a, b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + BytewiseComparator()->FindShortestSeparator(s, l); + } + virtual void FindShortSuccessor(std::string* key) const { + BytewiseComparator()->FindShortSuccessor(key); + } + }; + NewComparator cmp; + Options new_options = CurrentOptions(); + new_options.comparator = &cmp; + Status s = TryReopen(&new_options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, CustomComparator) { + class NumberComparator : public Comparator { + public: + virtual const char* Name() const { return "test.NumberComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return ToNumber(a) - ToNumber(b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + ToNumber(*s); // Check format + ToNumber(l); // Check format + } + virtual void FindShortSuccessor(std::string* key) const { + ToNumber(*key); // Check format + } + private: + static int ToNumber(const Slice& x) { + // Check that there are no extra characters. + ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']') + << EscapeString(x); + int val; + char ignored; + ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1) + << EscapeString(x); + return val; + } + }; + NumberComparator cmp; + Options new_options = CurrentOptions(); + new_options.create_if_missing = true; + new_options.comparator = &cmp; + new_options.filter_policy = NULL; // Cannot use bloom filters + new_options.write_buffer_size = 1000; // Compact more often + DestroyAndReopen(&new_options); + ASSERT_OK(Put("[10]", "ten")); + ASSERT_OK(Put("[0x14]", "twenty")); + for (int i = 0; i < 2; i++) { + ASSERT_EQ("ten", Get("[10]")); + ASSERT_EQ("ten", Get("[0xa]")); + ASSERT_EQ("twenty", Get("[20]")); + ASSERT_EQ("twenty", Get("[0x14]")); + ASSERT_EQ("NOT_FOUND", Get("[15]")); + ASSERT_EQ("NOT_FOUND", Get("[0xf]")); + Compact("[0]", "[9999]"); + } + + for (int run = 0; run < 2; run++) { + for (int i = 0; i < 1000; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "[%d]", i*10); + ASSERT_OK(Put(buf, buf)); + } + Compact("[0]", "[1000000]"); + } +} + +TEST(DBTest, ManualCompaction) { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) + << "Need to update this test to match kMaxMemCompactLevel"; + + MakeTables(3, "p", "q"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls before files + Compact("", "c"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls after files + Compact("r", "z"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range overlaps files + Compact("p1", "p9"); + ASSERT_EQ("0,0,1", FilesPerLevel()); + + // Populate a different range + MakeTables(3, "c", "e"); + ASSERT_EQ("1,1,2", FilesPerLevel()); + + // Compact just the new range + Compact("b", "f"); + ASSERT_EQ("0,0,2", FilesPerLevel()); + + // Compact all + MakeTables(1, "a", "z"); + ASSERT_EQ("0,1,2", FilesPerLevel()); + db_->CompactRange(NULL, NULL); + ASSERT_EQ("0,0,1", FilesPerLevel()); +} + +TEST(DBTest, DBOpen_Options) { + std::string dbname = test::TmpDir() + "/db_options_test"; + DestroyDB(dbname, Options()); + + // Does not exist, and create_if_missing == false: error + DB* db = NULL; + Options opts; + opts.create_if_missing = false; + Status s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL); + ASSERT_TRUE(db == NULL); + + // Does not exist, and create_if_missing == true: OK + opts.create_if_missing = true; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + // Does exist, and error_if_exists == true: error + opts.create_if_missing = false; + opts.error_if_exists = true; + s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL); + ASSERT_TRUE(db == NULL); + + // Does exist, and error_if_exists == false: OK + opts.create_if_missing = true; + opts.error_if_exists = false; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; +} + +TEST(DBTest, Locking) { + DB* db2 = NULL; + Status s = DB::Open(CurrentOptions(), dbname_, &db2); + ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db"; +} + +// Check that number of files does not grow when we are out of space +TEST(DBTest, NoSpace) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + const int num_files = CountFiles(); + env_->no_space_.Release_Store(env_); // Force out-of-space errors + env_->sleep_counter_.Reset(); + for (int i = 0; i < 5; i++) { + for (int level = 0; level < config::kNumLevels-1; level++) { + dbfull()->TEST_CompactRange(level, NULL, NULL); + } + } + env_->no_space_.Release_Store(NULL); + ASSERT_LT(CountFiles(), num_files + 3); + + // Check that compaction attempts slept after errors + ASSERT_GE(env_->sleep_counter_.Read(), 5); +} + +TEST(DBTest, NonWritableFileSystem) { + Options options = CurrentOptions(); + options.write_buffer_size = 1000; + options.env = env_; + Reopen(&options); + ASSERT_OK(Put("foo", "v1")); + env_->non_writable_.Release_Store(env_); // Force errors for new files + std::string big(100000, 'x'); + int errors = 0; + for (int i = 0; i < 20; i++) { + fprintf(stderr, "iter %d; errors %d\n", i, errors); + if (!Put("foo", big).ok()) { + errors++; + env_->SleepForMicroseconds(100000); + } + } + ASSERT_GT(errors, 0); + env_->non_writable_.Release_Store(NULL); +} + +TEST(DBTest, ManifestWriteError) { + // Test for the following problem: + // (a) Compaction produces file F + // (b) Log record containing F is written to MANIFEST file, but Sync() fails + // (c) GC deletes F + // (d) After reopening DB, reads fail since deleted F is named in log record + + // We iterate twice. In the second iteration, everything is the + // same except the log record never makes it to the MANIFEST file. + for (int iter = 0; iter < 2; iter++) { + port::AtomicPointer* error_type = (iter == 0) + ? &env_->manifest_sync_error_ + : &env_->manifest_write_error_; + + // Insert foo=>bar mapping + Options options = CurrentOptions(); + options.env = env_; + options.create_if_missing = true; + options.error_if_exists = false; + DestroyAndReopen(&options); + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Memtable compaction (will succeed) + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level + + // Merging compaction (will fail) + error_type->Release_Store(env_); + dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail + ASSERT_EQ("bar", Get("foo")); + + // Recovery: should not lose data + error_type->Release_Store(NULL); + Reopen(&options); + ASSERT_EQ("bar", Get("foo")); + } +} + +TEST(DBTest, FilesDeletedAfterCompaction) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + const int num_files = CountFiles(); + for (int i = 0; i < 10; i++) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + } + ASSERT_EQ(CountFiles(), num_files); +} + +TEST(DBTest, BloomFilter) { + env_->count_random_reads_ = true; + Options options = CurrentOptions(); + options.env = env_; + options.block_cache = NewLRUCache(0); // Prevent cache hits + options.filter_policy = NewBloomFilterPolicy(10); + Reopen(&options); + + // Populate multiple layers + const int N = 10000; + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i))); + } + Compact("a", "z"); + for (int i = 0; i < N; i += 100) { + ASSERT_OK(Put(Key(i), Key(i))); + } + dbfull()->TEST_CompactMemTable(); + + // Prevent auto compactions triggered by seeks + env_->delay_sstable_sync_.Release_Store(env_); + + // Lookup present keys. Should rarely read from small sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i), Get(Key(i))); + } + int reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d present => %d reads\n", N, reads); + ASSERT_GE(reads, N); + ASSERT_LE(reads, N + 2*N/100); + + // Lookup present keys. Should rarely read from either sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing")); + } + reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d missing => %d reads\n", N, reads); + ASSERT_LE(reads, 3*N/100); + + env_->delay_sstable_sync_.Release_Store(NULL); + Close(); + delete options.block_cache; + delete options.filter_policy; +} + +// Multi-threaded test: +namespace { + +static const int kNumThreads = 4; +static const int kTestSeconds = 10; +static const int kNumKeys = 1000; + +struct MTState { + DBTest* test; + port::AtomicPointer stop; + port::AtomicPointer counter[kNumThreads]; + port::AtomicPointer thread_done[kNumThreads]; +}; + +struct MTThread { + MTState* state; + int id; +}; + +static void MTThreadBody(void* arg) { + MTThread* t = reinterpret_cast(arg); + int id = t->id; + DB* db = t->state->test->db_; + uintptr_t counter = 0; + fprintf(stderr, "... starting thread %d\n", id); + Random rnd(1000 + id); + std::string value; + char valbuf[1500]; + while (t->state->stop.Acquire_Load() == NULL) { + t->state->counter[id].Release_Store(reinterpret_cast(counter)); + + int key = rnd.Uniform(kNumKeys); + char keybuf[20]; + snprintf(keybuf, sizeof(keybuf), "%016d", key); + + if (rnd.OneIn(2)) { + // Write values of the form . + // We add some padding for force compactions. + snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", + key, id, static_cast(counter)); + ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf))); + } else { + // Read a value and verify that it matches the pattern written above. + Status s = db->Get(ReadOptions(), Slice(keybuf), &value); + if (s.IsNotFound()) { + // Key has not yet been written + } else { + // Check that the writer thread counter is >= the counter in the value + ASSERT_OK(s); + int k, w, c; + ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value; + ASSERT_EQ(k, key); + ASSERT_GE(w, 0); + ASSERT_LT(w, kNumThreads); + ASSERT_LE(c, reinterpret_cast( + t->state->counter[w].Acquire_Load())); + } + } + counter++; + } + t->state->thread_done[id].Release_Store(t); + fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter)); +} + +} // namespace + +TEST(DBTest, MultiThreaded) { + do { + // Initialize state + MTState mt; + mt.test = this; + mt.stop.Release_Store(0); + for (int id = 0; id < kNumThreads; id++) { + mt.counter[id].Release_Store(0); + mt.thread_done[id].Release_Store(0); + } + + // Start threads + MTThread thread[kNumThreads]; + for (int id = 0; id < kNumThreads; id++) { + thread[id].state = &mt; + thread[id].id = id; + env_->StartThread(MTThreadBody, &thread[id]); + } + + // Let them run for a while + env_->SleepForMicroseconds(kTestSeconds * 1000000); + + // Stop the threads and wait for them to finish + mt.stop.Release_Store(&mt); + for (int id = 0; id < kNumThreads; id++) { + while (mt.thread_done[id].Acquire_Load() == NULL) { + env_->SleepForMicroseconds(100000); + } + } + } while (ChangeOptions()); +} + +namespace { +typedef std::map KVMap; +} + +class ModelDB: public DB { + public: + class ModelSnapshot : public Snapshot { + public: + KVMap map_; + }; + + explicit ModelDB(const Options& options): options_(options) { } + ~ModelDB() { } + virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { + return DB::Put(o, k, v); + } + virtual Status Delete(const WriteOptions& o, const Slice& key) { + return DB::Delete(o, key); + } + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) { + assert(false); // Not implemented + return Status::NotFound(key); + } + virtual Iterator* NewIterator(const ReadOptions& options) { + if (options.snapshot == NULL) { + KVMap* saved = new KVMap; + *saved = map_; + return new ModelIter(saved, true); + } else { + const KVMap* snapshot_state = + &(reinterpret_cast(options.snapshot)->map_); + return new ModelIter(snapshot_state, false); + } + } + virtual const Snapshot* GetSnapshot() { + ModelSnapshot* snapshot = new ModelSnapshot; + snapshot->map_ = map_; + return snapshot; + } + + virtual void ReleaseSnapshot(const Snapshot* snapshot) { + delete reinterpret_cast(snapshot); + } + virtual Status Write(const WriteOptions& options, WriteBatch* batch) { + class Handler : public WriteBatch::Handler { + public: + KVMap* map_; + virtual void Put(const Slice& key, const Slice& value) { + (*map_)[key.ToString()] = value.ToString(); + } + virtual void Delete(const Slice& key) { + map_->erase(key.ToString()); + } + }; + Handler handler; + handler.map_ = &map_; + return batch->Iterate(&handler); + } + + virtual bool GetProperty(const Slice& property, std::string* value) { + return false; + } + virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) { + for (int i = 0; i < n; i++) { + sizes[i] = 0; + } + } + virtual void CompactRange(const Slice* start, const Slice* end) { + } + + private: + class ModelIter: public Iterator { + public: + ModelIter(const KVMap* map, bool owned) + : map_(map), owned_(owned), iter_(map_->end()) { + } + ~ModelIter() { + if (owned_) delete map_; + } + virtual bool Valid() const { return iter_ != map_->end(); } + virtual void SeekToFirst() { iter_ = map_->begin(); } + virtual void SeekToLast() { + if (map_->empty()) { + iter_ = map_->end(); + } else { + iter_ = map_->find(map_->rbegin()->first); + } + } + virtual void Seek(const Slice& k) { + iter_ = map_->lower_bound(k.ToString()); + } + virtual void Next() { ++iter_; } + virtual void Prev() { --iter_; } + virtual Slice key() const { return iter_->first; } + virtual Slice value() const { return iter_->second; } + virtual Status status() const { return Status::OK(); } + private: + const KVMap* const map_; + const bool owned_; // Do we own map_ + KVMap::const_iterator iter_; + }; + const Options options_; + KVMap map_; +}; + +static std::string RandomKey(Random* rnd) { + int len = (rnd->OneIn(3) + ? 1 // Short sometimes to encourage collisions + : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10))); + return test::RandomKey(rnd, len); +} + +static bool CompareIterators(int step, + DB* model, + DB* db, + const Snapshot* model_snap, + const Snapshot* db_snap) { + ReadOptions options; + options.snapshot = model_snap; + Iterator* miter = model->NewIterator(options); + options.snapshot = db_snap; + Iterator* dbiter = db->NewIterator(options); + bool ok = true; + int count = 0; + for (miter->SeekToFirst(), dbiter->SeekToFirst(); + ok && miter->Valid() && dbiter->Valid(); + miter->Next(), dbiter->Next()) { + count++; + if (miter->key().compare(dbiter->key()) != 0) { + fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(dbiter->key()).c_str()); + ok = false; + break; + } + + if (miter->value().compare(dbiter->value()) != 0) { + fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(miter->value()).c_str(), + EscapeString(miter->value()).c_str()); + ok = false; + } + } + + if (ok) { + if (miter->Valid() != dbiter->Valid()) { + fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n", + step, miter->Valid(), dbiter->Valid()); + ok = false; + } + } + fprintf(stderr, "%d entries compared: ok=%d\n", count, ok); + delete miter; + delete dbiter; + return ok; +} + +TEST(DBTest, Randomized) { + Random rnd(test::RandomSeed()); + do { + ModelDB model(CurrentOptions()); + const int N = 10000; + const Snapshot* model_snap = NULL; + const Snapshot* db_snap = NULL; + std::string k, v; + for (int step = 0; step < N; step++) { + if (step % 100 == 0) { + fprintf(stderr, "Step %d of %d\n", step, N); + } + // TODO(sanjay): Test Get() works + int p = rnd.Uniform(100); + if (p < 45) { // Put + k = RandomKey(&rnd); + v = RandomString(&rnd, + rnd.OneIn(20) + ? 100 + rnd.Uniform(100) + : rnd.Uniform(8)); + ASSERT_OK(model.Put(WriteOptions(), k, v)); + ASSERT_OK(db_->Put(WriteOptions(), k, v)); + + } else if (p < 90) { // Delete + k = RandomKey(&rnd); + ASSERT_OK(model.Delete(WriteOptions(), k)); + ASSERT_OK(db_->Delete(WriteOptions(), k)); + + + } else { // Multi-element batch + WriteBatch b; + const int num = rnd.Uniform(8); + for (int i = 0; i < num; i++) { + if (i == 0 || !rnd.OneIn(10)) { + k = RandomKey(&rnd); + } else { + // Periodically re-use the same key from the previous iter, so + // we have multiple entries in the write batch for the same key + } + if (rnd.OneIn(2)) { + v = RandomString(&rnd, rnd.Uniform(10)); + b.Put(k, v); + } else { + b.Delete(k); + } + } + ASSERT_OK(model.Write(WriteOptions(), &b)); + ASSERT_OK(db_->Write(WriteOptions(), &b)); + } + + if ((step % 100) == 0) { + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap)); + // Save a snapshot from each DB this time that we'll use next + // time we compare things, to make sure the current state is + // preserved with the snapshot + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + + Reopen(); + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + + model_snap = model.GetSnapshot(); + db_snap = db_->GetSnapshot(); + } + } + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + } while (ChangeOptions()); +} + +std::string MakeKey(unsigned int num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%016u", num); + return std::string(buf); +} + +void BM_LogAndApply(int iters, int num_base_files) { + std::string dbname = test::TmpDir() + "/leveldb_test_benchmark"; + DestroyDB(dbname, Options()); + + DB* db = NULL; + Options opts; + opts.create_if_missing = true; + Status s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + Env* env = Env::Default(); + + port::Mutex mu; + MutexLock l(&mu); + + InternalKeyComparator cmp(BytewiseComparator()); + Options options; + VersionSet vset(dbname, &options, NULL, &cmp); + ASSERT_OK(vset.Recover()); + VersionEdit vbase; + uint64_t fnum = 1; + for (int i = 0; i < num_base_files; i++) { + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vbase.AddFile(2, fnum++, 1 /* file size */, start, limit); + } + ASSERT_OK(vset.LogAndApply(&vbase, &mu)); + + uint64_t start_micros = env->NowMicros(); + + for (int i = 0; i < iters; i++) { + VersionEdit vedit; + vedit.DeleteFile(2, fnum); + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vedit.AddFile(2, fnum++, 1 /* file size */, start, limit); + vset.LogAndApply(&vedit, &mu); + } + uint64_t stop_micros = env->NowMicros(); + unsigned int us = stop_micros - start_micros; + char buf[16]; + snprintf(buf, sizeof(buf), "%d", num_base_files); + fprintf(stderr, + "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", + buf, iters, us, ((float)us) / iters); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + if (argc > 1 && std::string(argv[1]) == "--benchmark") { + leveldb::BM_LogAndApply(1000, 1); + leveldb::BM_LogAndApply(1000, 100); + leveldb::BM_LogAndApply(1000, 10000); + leveldb::BM_LogAndApply(100, 100000); + return 0; + } + + return leveldb::test::RunAllTests(); +} diff --git a/db/dbformat.cc b/db/dbformat.cc new file mode 100644 index 000000000..28e11b398 --- /dev/null +++ b/db/dbformat.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { + +static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { + assert(seq <= kMaxSequenceNumber); + assert(t <= kValueTypeForSeek); + return (seq << 8) | t; +} + +void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { + result->append(key.user_key.data(), key.user_key.size()); + PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); +} + +std::string ParsedInternalKey::DebugString() const { + char buf[50]; + snprintf(buf, sizeof(buf), "' @ %llu : %d", + (unsigned long long) sequence, + int(type)); + std::string result = "'"; + result += user_key.ToString(); + result += buf; + return result; +} + +std::string InternalKey::DebugString() const { + std::string result; + ParsedInternalKey parsed; + if (ParseInternalKey(rep_, &parsed)) { + result = parsed.DebugString(); + } else { + result = "(bad)"; + result.append(EscapeString(rep_)); + } + return result; +} + +const char* InternalKeyComparator::Name() const { + return "leveldb.InternalKeyComparator"; +} + +int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { + // Order by: + // increasing user key (according to user-supplied comparator) + // decreasing sequence number + // decreasing type (though sequence# should be enough to disambiguate) + int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); + if (r == 0) { + const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); + const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); + if (anum > bnum) { + r = -1; + } else if (anum < bnum) { + r = +1; + } + } + return r; +} + +void InternalKeyComparator::FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Attempt to shorten the user portion of the key + Slice user_start = ExtractUserKey(*start); + Slice user_limit = ExtractUserKey(limit); + std::string tmp(user_start.data(), user_start.size()); + user_comparator_->FindShortestSeparator(&tmp, user_limit); + if (tmp.size() < user_start.size() && + user_comparator_->Compare(user_start, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*start, tmp) < 0); + assert(this->Compare(tmp, limit) < 0); + start->swap(tmp); + } +} + +void InternalKeyComparator::FindShortSuccessor(std::string* key) const { + Slice user_key = ExtractUserKey(*key); + std::string tmp(user_key.data(), user_key.size()); + user_comparator_->FindShortSuccessor(&tmp); + if (tmp.size() < user_key.size() && + user_comparator_->Compare(user_key, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*key, tmp) < 0); + key->swap(tmp); + } +} + +const char* InternalFilterPolicy::Name() const { + return user_policy_->Name(); +} + +void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, + std::string* dst) const { + // We rely on the fact that the code in table.cc does not mind us + // adjusting keys[]. + Slice* mkey = const_cast(keys); + for (int i = 0; i < n; i++) { + mkey[i] = ExtractUserKey(keys[i]); + // TODO(sanjay): Suppress dups? + } + user_policy_->CreateFilter(keys, n, dst); +} + +bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { + return user_policy_->KeyMayMatch(ExtractUserKey(key), f); +} + +LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { + size_t usize = user_key.size(); + size_t needed = usize + 13; // A conservative estimate + char* dst; + if (needed <= sizeof(space_)) { + dst = space_; + } else { + dst = new char[needed]; + } + start_ = dst; + dst = EncodeVarint32(dst, usize + 8); + kstart_ = dst; + memcpy(dst, user_key.data(), usize); + dst += usize; + EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); + dst += 8; + end_ = dst; +} + +} // namespace leveldb diff --git a/db/dbformat.h b/db/dbformat.h new file mode 100644 index 000000000..f7f64dafb --- /dev/null +++ b/db/dbformat.h @@ -0,0 +1,227 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_FORMAT_H_ +#define STORAGE_LEVELDB_DB_FORMAT_H_ + +#include +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "leveldb/slice.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +// Grouping of constants. We may want to make some of these +// parameters set via options. +namespace config { +static const int kNumLevels = 7; + +// Level-0 compaction is started when we hit this many files. +static const int kL0_CompactionTrigger = 4; + +// Soft limit on number of level-0 files. We slow down writes at this point. +static const int kL0_SlowdownWritesTrigger = 8; + +// Maximum number of level-0 files. We stop writes at this point. +static const int kL0_StopWritesTrigger = 12; + +// Maximum level to which a new compacted memtable is pushed if it +// does not create overlap. We try to push to level 2 to avoid the +// relatively expensive level 0=>1 compactions and to avoid some +// expensive manifest file operations. We do not push all the way to +// the largest level since that can generate a lot of wasted disk +// space if the same key space is being repeatedly overwritten. +static const int kMaxMemCompactLevel = 2; + +} // namespace config + +class InternalKey; + +// Value types encoded as the last component of internal keys. +// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk +// data structures. +enum ValueType { + kTypeDeletion = 0x0, + kTypeValue = 0x1 +}; +// kValueTypeForSeek defines the ValueType that should be passed when +// constructing a ParsedInternalKey object for seeking to a particular +// sequence number (since we sort sequence numbers in decreasing order +// and the value type is embedded as the low 8 bits in the sequence +// number in internal keys, we need to use the highest-numbered +// ValueType, not the lowest). +static const ValueType kValueTypeForSeek = kTypeValue; + +typedef uint64_t SequenceNumber; + +// We leave eight bits empty at the bottom so a type and sequence# +// can be packed together into 64-bits. +static const SequenceNumber kMaxSequenceNumber = + ((0x1ull << 56) - 1); + +struct ParsedInternalKey { + Slice user_key; + SequenceNumber sequence; + ValueType type; + + ParsedInternalKey() { } // Intentionally left uninitialized (for speed) + ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) + : user_key(u), sequence(seq), type(t) { } + std::string DebugString() const; +}; + +// Return the length of the encoding of "key". +inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { + return key.user_key.size() + 8; +} + +// Append the serialization of "key" to *result. +extern void AppendInternalKey(std::string* result, + const ParsedInternalKey& key); + +// Attempt to parse an internal key from "internal_key". On success, +// stores the parsed data in "*result", and returns true. +// +// On error, returns false, leaves "*result" in an undefined state. +extern bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result); + +// Returns the user key portion of an internal key. +inline Slice ExtractUserKey(const Slice& internal_key) { + assert(internal_key.size() >= 8); + return Slice(internal_key.data(), internal_key.size() - 8); +} + +inline ValueType ExtractValueType(const Slice& internal_key) { + assert(internal_key.size() >= 8); + const size_t n = internal_key.size(); + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + return static_cast(c); +} + +// A comparator for internal keys that uses a specified comparator for +// the user key portion and breaks ties by decreasing sequence number. +class InternalKeyComparator : public Comparator { + private: + const Comparator* user_comparator_; + public: + explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { } + virtual const char* Name() const; + virtual int Compare(const Slice& a, const Slice& b) const; + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const; + virtual void FindShortSuccessor(std::string* key) const; + + const Comparator* user_comparator() const { return user_comparator_; } + + int Compare(const InternalKey& a, const InternalKey& b) const; +}; + +// Filter policy wrapper that converts from internal keys to user keys +class InternalFilterPolicy : public FilterPolicy { + private: + const FilterPolicy* const user_policy_; + public: + explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { } + virtual const char* Name() const; + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; +}; + +// Modules in this directory should keep internal keys wrapped inside +// the following class instead of plain strings so that we do not +// incorrectly use string comparisons instead of an InternalKeyComparator. +class InternalKey { + private: + std::string rep_; + public: + InternalKey() { } // Leave rep_ as empty to indicate it is invalid + InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { + AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); + } + + void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } + Slice Encode() const { + assert(!rep_.empty()); + return rep_; + } + + Slice user_key() const { return ExtractUserKey(rep_); } + + void SetFrom(const ParsedInternalKey& p) { + rep_.clear(); + AppendInternalKey(&rep_, p); + } + + void Clear() { rep_.clear(); } + + std::string DebugString() const; +}; + +inline int InternalKeyComparator::Compare( + const InternalKey& a, const InternalKey& b) const { + return Compare(a.Encode(), b.Encode()); +} + +inline bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result) { + const size_t n = internal_key.size(); + if (n < 8) return false; + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + result->sequence = num >> 8; + result->type = static_cast(c); + result->user_key = Slice(internal_key.data(), n - 8); + return (c <= static_cast(kTypeValue)); +} + +// A helper class useful for DBImpl::Get() +class LookupKey { + public: + // Initialize *this for looking up user_key at a snapshot with + // the specified sequence number. + LookupKey(const Slice& user_key, SequenceNumber sequence); + + ~LookupKey(); + + // Return a key suitable for lookup in a MemTable. + Slice memtable_key() const { return Slice(start_, end_ - start_); } + + // Return an internal key (suitable for passing to an internal iterator) + Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } + + // Return the user key + Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } + + private: + // We construct a char array of the form: + // klength varint32 <-- start_ + // userkey char[klength] <-- kstart_ + // tag uint64 + // <-- end_ + // The array is a suitable MemTable key. + // The suffix starting with "userkey" can be used as an InternalKey. + const char* start_; + const char* kstart_; + const char* end_; + char space_[200]; // Avoid allocation for short keys + + // No copying allowed + LookupKey(const LookupKey&); + void operator=(const LookupKey&); +}; + +inline LookupKey::~LookupKey() { + if (start_ != space_) delete[] start_; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FORMAT_H_ diff --git a/db/dbformat_test.cc b/db/dbformat_test.cc new file mode 100644 index 000000000..5d82f5d31 --- /dev/null +++ b/db/dbformat_test.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/dbformat.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string IKey(const std::string& user_key, + uint64_t seq, + ValueType vt) { + std::string encoded; + AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt)); + return encoded; +} + +static std::string Shorten(const std::string& s, const std::string& l) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l); + return result; +} + +static std::string ShortSuccessor(const std::string& s) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result); + return result; +} + +static void TestKey(const std::string& key, + uint64_t seq, + ValueType vt) { + std::string encoded = IKey(key, seq, vt); + + Slice in(encoded); + ParsedInternalKey decoded("", 0, kTypeValue); + + ASSERT_TRUE(ParseInternalKey(in, &decoded)); + ASSERT_EQ(key, decoded.user_key.ToString()); + ASSERT_EQ(seq, decoded.sequence); + ASSERT_EQ(vt, decoded.type); + + ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded)); +} + +class FormatTest { }; + +TEST(FormatTest, InternalKey_EncodeDecode) { + const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" }; + const uint64_t seq[] = { + 1, 2, 3, + (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1, + (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1, + (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1 + }; + for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) { + for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) { + TestKey(keys[k], seq[s], kTypeValue); + TestKey("hello", 1, kTypeDeletion); + } + } +} + +TEST(FormatTest, InternalKeyShortSeparator) { + // When user keys are same + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 99, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 101, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeDeletion))); + + // When user keys are misordered + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("bar", 99, kTypeValue))); + + // When user keys are different, but correctly ordered + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("foo", 100, kTypeValue), + IKey("hello", 200, kTypeValue))); + + // When start user key is prefix of limit user key + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foobar", 200, kTypeValue))); + + // When limit user key is prefix of start user key + ASSERT_EQ(IKey("foobar", 100, kTypeValue), + Shorten(IKey("foobar", 100, kTypeValue), + IKey("foo", 200, kTypeValue))); +} + +TEST(FormatTest, InternalKeyShortestSuccessor) { + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + ShortSuccessor(IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue), + ShortSuccessor(IKey("\xff\xff", 100, kTypeValue))); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/filename.cc b/db/filename.cc new file mode 100644 index 000000000..3c4d49f64 --- /dev/null +++ b/db/filename.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "db/filename.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "util/logging.h" + +namespace leveldb { + +// A utility routine: write "data" to the named file and Sync() it. +extern Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname); + +static std::string MakeFileName(const std::string& name, uint64_t number, + const char* suffix) { + char buf[100]; + snprintf(buf, sizeof(buf), "/%06llu.%s", + static_cast(number), + suffix); + return name + buf; +} + +std::string LogFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "log"); +} + +std::string TableFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "sst"); +} + +std::string DescriptorFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + char buf[100]; + snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", + static_cast(number)); + return dbname + buf; +} + +std::string CurrentFileName(const std::string& dbname) { + return dbname + "/CURRENT"; +} + +std::string LockFileName(const std::string& dbname) { + return dbname + "/LOCK"; +} + +std::string TempFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "dbtmp"); +} + +std::string InfoLogFileName(const std::string& dbname) { + return dbname + "/LOG"; +} + +// Return the name of the old info log file for "dbname". +std::string OldInfoLogFileName(const std::string& dbname) { + return dbname + "/LOG.old"; +} + + +// Owned filenames have the form: +// dbname/CURRENT +// dbname/LOCK +// dbname/LOG +// dbname/LOG.old +// dbname/MANIFEST-[0-9]+ +// dbname/[0-9]+.(log|sst) +bool ParseFileName(const std::string& fname, + uint64_t* number, + FileType* type) { + Slice rest(fname); + if (rest == "CURRENT") { + *number = 0; + *type = kCurrentFile; + } else if (rest == "LOCK") { + *number = 0; + *type = kDBLockFile; + } else if (rest == "LOG" || rest == "LOG.old") { + *number = 0; + *type = kInfoLogFile; + } else if (rest.starts_with("MANIFEST-")) { + rest.remove_prefix(strlen("MANIFEST-")); + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + if (!rest.empty()) { + return false; + } + *type = kDescriptorFile; + *number = num; + } else { + // Avoid strtoull() to keep filename format independent of the + // current locale + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + Slice suffix = rest; + if (suffix == Slice(".log")) { + *type = kLogFile; + } else if (suffix == Slice(".sst")) { + *type = kTableFile; + } else if (suffix == Slice(".dbtmp")) { + *type = kTempFile; + } else { + return false; + } + *number = num; + } + return true; +} + +Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number) { + // Remove leading "dbname/" and add newline to manifest file name + std::string manifest = DescriptorFileName(dbname, descriptor_number); + Slice contents = manifest; + assert(contents.starts_with(dbname + "/")); + contents.remove_prefix(dbname.size() + 1); + std::string tmp = TempFileName(dbname, descriptor_number); + Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); + if (s.ok()) { + s = env->RenameFile(tmp, CurrentFileName(dbname)); + } + if (!s.ok()) { + env->DeleteFile(tmp); + } + return s; +} + +} // namespace leveldb diff --git a/db/filename.h b/db/filename.h new file mode 100644 index 000000000..d5d09b114 --- /dev/null +++ b/db/filename.h @@ -0,0 +1,80 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// File names used by DB code + +#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ +#define STORAGE_LEVELDB_DB_FILENAME_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +enum FileType { + kLogFile, + kDBLockFile, + kTableFile, + kDescriptorFile, + kCurrentFile, + kTempFile, + kInfoLogFile // Either the current one, or an old one +}; + +// Return the name of the log file with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string LogFileName(const std::string& dbname, uint64_t number); + +// Return the name of the sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string TableFileName(const std::string& dbname, uint64_t number); + +// Return the name of the descriptor file for the db named by +// "dbname" and the specified incarnation number. The result will be +// prefixed with "dbname". +extern std::string DescriptorFileName(const std::string& dbname, + uint64_t number); + +// Return the name of the current file. This file contains the name +// of the current manifest file. The result will be prefixed with +// "dbname". +extern std::string CurrentFileName(const std::string& dbname); + +// Return the name of the lock file for the db named by +// "dbname". The result will be prefixed with "dbname". +extern std::string LockFileName(const std::string& dbname); + +// Return the name of a temporary file owned by the db named "dbname". +// The result will be prefixed with "dbname". +extern std::string TempFileName(const std::string& dbname, uint64_t number); + +// Return the name of the info log file for "dbname". +extern std::string InfoLogFileName(const std::string& dbname); + +// Return the name of the old info log file for "dbname". +extern std::string OldInfoLogFileName(const std::string& dbname); + +// If filename is a leveldb file, store the type of the file in *type. +// The number encoded in the filename is stored in *number. If the +// filename was successfully parsed, returns true. Else return false. +extern bool ParseFileName(const std::string& filename, + uint64_t* number, + FileType* type); + +// Make the CURRENT file point to the descriptor file with the +// specified number. +extern Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number); + + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/db/filename_test.cc b/db/filename_test.cc new file mode 100644 index 000000000..47353d6c9 --- /dev/null +++ b/db/filename_test.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/filename.h" + +#include "db/dbformat.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +class FileNameTest { }; + +TEST(FileNameTest, Parse) { + Slice db; + FileType type; + uint64_t number; + + // Successful parses + static struct { + const char* fname; + uint64_t number; + FileType type; + } cases[] = { + { "100.log", 100, kLogFile }, + { "0.log", 0, kLogFile }, + { "0.sst", 0, kTableFile }, + { "CURRENT", 0, kCurrentFile }, + { "LOCK", 0, kDBLockFile }, + { "MANIFEST-2", 2, kDescriptorFile }, + { "MANIFEST-7", 7, kDescriptorFile }, + { "LOG", 0, kInfoLogFile }, + { "LOG.old", 0, kInfoLogFile }, + { "18446744073709551615.log", 18446744073709551615ull, kLogFile }, + }; + for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + std::string f = cases[i].fname; + ASSERT_TRUE(ParseFileName(f, &number, &type)) << f; + ASSERT_EQ(cases[i].type, type) << f; + ASSERT_EQ(cases[i].number, number) << f; + } + + // Errors + static const char* errors[] = { + "", + "foo", + "foo-dx-100.log", + ".log", + "", + "manifest", + "CURREN", + "CURRENTX", + "MANIFES", + "MANIFEST", + "MANIFEST-", + "XMANIFEST-3", + "MANIFEST-3x", + "LOC", + "LOCKx", + "LO", + "LOGx", + "18446744073709551616.log", + "184467440737095516150.log", + "100", + "100.", + "100.lop" + }; + for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { + std::string f = errors[i]; + ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; + }; +} + +TEST(FileNameTest, Construction) { + uint64_t number; + FileType type; + std::string fname; + + fname = CurrentFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kCurrentFile, type); + + fname = LockFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kDBLockFile, type); + + fname = LogFileName("foo", 192); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(192, number); + ASSERT_EQ(kLogFile, type); + + fname = TableFileName("bar", 200); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(200, number); + ASSERT_EQ(kTableFile, type); + + fname = DescriptorFileName("bar", 100); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(100, number); + ASSERT_EQ(kDescriptorFile, type); + + fname = TempFileName("tmp", 999); + ASSERT_EQ("tmp/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(999, number); + ASSERT_EQ(kTempFile, type); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/leveldb_main.cc b/db/leveldb_main.cc new file mode 100644 index 000000000..995d76107 --- /dev/null +++ b/db/leveldb_main.cc @@ -0,0 +1,238 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" + +namespace leveldb { + +namespace { + +bool GuessType(const std::string& fname, FileType* type) { + size_t pos = fname.rfind('/'); + std::string basename; + if (pos == std::string::npos) { + basename = fname; + } else { + basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); + } + uint64_t ignored; + return ParseFileName(basename, &ignored, type); +} + +// Notified when log reader encounters corruption. +class CorruptionReporter : public log::Reader::Reporter { + public: + virtual void Corruption(size_t bytes, const Status& status) { + printf("corruption: %d bytes; %s\n", + static_cast(bytes), + status.ToString().c_str()); + } +}; + +// Print contents of a log file. (*func)() is called on every record. +bool PrintLogContents(Env* env, const std::string& fname, + void (*func)(Slice)) { + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + return false; + } + CorruptionReporter reporter; + log::Reader reader(file, &reporter, true, 0); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch)) { + printf("--- offset %llu; ", + static_cast(reader.LastRecordOffset())); + (*func)(record); + } + delete file; + return true; +} + +// Called on every item found in a WriteBatch. +class WriteBatchItemPrinter : public WriteBatch::Handler { + public: + uint64_t offset_; + uint64_t sequence_; + + virtual void Put(const Slice& key, const Slice& value) { + printf(" put '%s' '%s'\n", + EscapeString(key).c_str(), + EscapeString(value).c_str()); + } + virtual void Delete(const Slice& key) { + printf(" del '%s'\n", + EscapeString(key).c_str()); + } +}; + + +// Called on every log record (each one of which is a WriteBatch) +// found in a kLogFile. +static void WriteBatchPrinter(Slice record) { + if (record.size() < 12) { + printf("log record length %d is too small\n", + static_cast(record.size())); + return; + } + WriteBatch batch; + WriteBatchInternal::SetContents(&batch, record); + printf("sequence %llu\n", + static_cast(WriteBatchInternal::Sequence(&batch))); + WriteBatchItemPrinter batch_item_printer; + Status s = batch.Iterate(&batch_item_printer); + if (!s.ok()) { + printf(" error: %s\n", s.ToString().c_str()); + } +} + +bool DumpLog(Env* env, const std::string& fname) { + return PrintLogContents(env, fname, WriteBatchPrinter); +} + +// Called on every log record (each one of which is a WriteBatch) +// found in a kDescriptorFile. +static void VersionEditPrinter(Slice record) { + VersionEdit edit; + Status s = edit.DecodeFrom(record); + if (!s.ok()) { + printf("%s\n", s.ToString().c_str()); + return; + } + printf("%s", edit.DebugString().c_str()); +} + +bool DumpDescriptor(Env* env, const std::string& fname) { + return PrintLogContents(env, fname, VersionEditPrinter); +} + +bool DumpTable(Env* env, const std::string& fname) { + uint64_t file_size; + RandomAccessFile* file = NULL; + Table* table = NULL; + Status s = env->GetFileSize(fname, &file_size); + if (s.ok()) { + s = env->NewRandomAccessFile(fname, &file); + } + if (s.ok()) { + // We use the default comparator, which may or may not match the + // comparator used in this database. However this should not cause + // problems since we only use Table operations that do not require + // any comparisons. In particular, we do not call Seek or Prev. + s = Table::Open(Options(), file, file_size, &table); + } + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + delete table; + delete file; + return false; + } + + ReadOptions ro; + ro.fill_cache = false; + Iterator* iter = table->NewIterator(ro); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey key; + if (!ParseInternalKey(iter->key(), &key)) { + printf("badkey '%s' => '%s'\n", + EscapeString(iter->key()).c_str(), + EscapeString(iter->value()).c_str()); + } else { + char kbuf[20]; + const char* type; + if (key.type == kTypeDeletion) { + type = "del"; + } else if (key.type == kTypeValue) { + type = "val"; + } else { + snprintf(kbuf, sizeof(kbuf), "%d", static_cast(key.type)); + type = kbuf; + } + printf("'%s' @ %8llu : %s => '%s'\n", + EscapeString(key.user_key).c_str(), + static_cast(key.sequence), + type, + EscapeString(iter->value()).c_str()); + } + } + s = iter->status(); + if (!s.ok()) { + printf("iterator error: %s\n", s.ToString().c_str()); + } + + delete iter; + delete table; + delete file; + return true; +} + +bool DumpFile(Env* env, const std::string& fname) { + FileType ftype; + if (!GuessType(fname, &ftype)) { + fprintf(stderr, "%s: unknown file type\n", fname.c_str()); + return false; + } + switch (ftype) { + case kLogFile: return DumpLog(env, fname); + case kDescriptorFile: return DumpDescriptor(env, fname); + case kTableFile: return DumpTable(env, fname); + + default: { + fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str()); + break; + } + } + return false; +} + +bool HandleDumpCommand(Env* env, char** files, int num) { + bool ok = true; + for (int i = 0; i < num; i++) { + ok &= DumpFile(env, files[i]); + } + return ok; +} + +} +} // namespace leveldb + +static void Usage() { + fprintf( + stderr, + "Usage: leveldbutil command...\n" + " dump files... -- dump contents of specified files\n" + ); +} + +int main(int argc, char** argv) { + leveldb::Env* env = leveldb::Env::Default(); + bool ok = true; + if (argc < 2) { + Usage(); + ok = false; + } else { + std::string command = argv[1]; + if (command == "dump") { + ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); + } else { + Usage(); + ok = false; + } + } + return (ok ? 0 : 1); +} diff --git a/db/log_format.h b/db/log_format.h new file mode 100644 index 000000000..2690cb978 --- /dev/null +++ b/db/log_format.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Log format information shared by reader and writer. +// See ../doc/log_format.txt for more detail. + +#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ +#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ + +namespace leveldb { +namespace log { + +enum RecordType { + // Zero is reserved for preallocated files + kZeroType = 0, + + kFullType = 1, + + // For fragments + kFirstType = 2, + kMiddleType = 3, + kLastType = 4 +}; +static const int kMaxRecordType = kLastType; + +static const int kBlockSize = 32768; + +// Header is checksum (4 bytes), type (1 byte), length (2 bytes). +static const int kHeaderSize = 4 + 1 + 2; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/db/log_reader.cc b/db/log_reader.cc new file mode 100644 index 000000000..b35f115aa --- /dev/null +++ b/db/log_reader.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Reader::Reporter::~Reporter() { +} + +Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset) + : file_(file), + reporter_(reporter), + checksum_(checksum), + backing_store_(new char[kBlockSize]), + buffer_(), + eof_(false), + last_record_offset_(0), + end_of_buffer_offset_(0), + initial_offset_(initial_offset) { +} + +Reader::~Reader() { + delete[] backing_store_; +} + +bool Reader::SkipToInitialBlock() { + size_t offset_in_block = initial_offset_ % kBlockSize; + uint64_t block_start_location = initial_offset_ - offset_in_block; + + // Don't search a block if we'd be in the trailer + if (offset_in_block > kBlockSize - 6) { + offset_in_block = 0; + block_start_location += kBlockSize; + } + + end_of_buffer_offset_ = block_start_location; + + // Skip to start of first block that can contain the initial record + if (block_start_location > 0) { + Status skip_status = file_->Skip(block_start_location); + if (!skip_status.ok()) { + ReportDrop(block_start_location, skip_status); + return false; + } + } + + return true; +} + +bool Reader::ReadRecord(Slice* record, std::string* scratch) { + if (last_record_offset_ < initial_offset_) { + if (!SkipToInitialBlock()) { + return false; + } + } + + scratch->clear(); + record->clear(); + bool in_fragmented_record = false; + // Record offset of the logical record that we're reading + // 0 is a dummy value to make compilers happy + uint64_t prospective_record_offset = 0; + + Slice fragment; + while (true) { + uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size(); + const unsigned int record_type = ReadPhysicalRecord(&fragment); + switch (record_type) { + case kFullType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(1)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->clear(); + *record = fragment; + last_record_offset_ = prospective_record_offset; + return true; + + case kFirstType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(2)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->assign(fragment.data(), fragment.size()); + in_fragmented_record = true; + break; + + case kMiddleType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(1)"); + } else { + scratch->append(fragment.data(), fragment.size()); + } + break; + + case kLastType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(2)"); + } else { + scratch->append(fragment.data(), fragment.size()); + *record = Slice(*scratch); + last_record_offset_ = prospective_record_offset; + return true; + } + break; + + case kEof: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "partial record without end(3)"); + scratch->clear(); + } + return false; + + case kBadRecord: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "error in middle of record"); + in_fragmented_record = false; + scratch->clear(); + } + break; + + default: { + char buf[40]; + snprintf(buf, sizeof(buf), "unknown record type %u", record_type); + ReportCorruption( + (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), + buf); + in_fragmented_record = false; + scratch->clear(); + break; + } + } + } + return false; +} + +uint64_t Reader::LastRecordOffset() { + return last_record_offset_; +} + +void Reader::ReportCorruption(size_t bytes, const char* reason) { + ReportDrop(bytes, Status::Corruption(reason)); +} + +void Reader::ReportDrop(size_t bytes, const Status& reason) { + if (reporter_ != NULL && + end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { + reporter_->Corruption(bytes, reason); + } +} + +unsigned int Reader::ReadPhysicalRecord(Slice* result) { + while (true) { + if (buffer_.size() < kHeaderSize) { + if (!eof_) { + // Last read was a full read, so this is a trailer to skip + buffer_.clear(); + Status status = file_->Read(kBlockSize, &buffer_, backing_store_); + end_of_buffer_offset_ += buffer_.size(); + if (!status.ok()) { + buffer_.clear(); + ReportDrop(kBlockSize, status); + eof_ = true; + return kEof; + } else if (buffer_.size() < kBlockSize) { + eof_ = true; + } + continue; + } else if (buffer_.size() == 0) { + // End of file + return kEof; + } else { + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "truncated record at end of file"); + return kEof; + } + } + + // Parse the header + const char* header = buffer_.data(); + const uint32_t a = static_cast(header[4]) & 0xff; + const uint32_t b = static_cast(header[5]) & 0xff; + const unsigned int type = header[6]; + const uint32_t length = a | (b << 8); + if (kHeaderSize + length > buffer_.size()) { + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "bad record length"); + return kBadRecord; + } + + if (type == kZeroType && length == 0) { + // Skip zero length record without reporting any drops since + // such records are produced by the mmap based writing code in + // env_posix.cc that preallocates file regions. + buffer_.clear(); + return kBadRecord; + } + + // Check crc + if (checksum_) { + uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); + uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); + if (actual_crc != expected_crc) { + // Drop the rest of the buffer since "length" itself may have + // been corrupted and if we trust it, we could find some + // fragment of a real log record that just happens to look + // like a valid log record. + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "checksum mismatch"); + return kBadRecord; + } + } + + buffer_.remove_prefix(kHeaderSize + length); + + // Skip physical record that started before initial_offset_ + if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < + initial_offset_) { + result->clear(); + return kBadRecord; + } + + *result = Slice(header + kHeaderSize, length); + return type; + } +} + +} // namespace log +} // namespace leveldb diff --git a/db/log_reader.h b/db/log_reader.h new file mode 100644 index 000000000..82d4bee68 --- /dev/null +++ b/db/log_reader.h @@ -0,0 +1,108 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_ +#define STORAGE_LEVELDB_DB_LOG_READER_H_ + +#include + +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class SequentialFile; + +namespace log { + +class Reader { + public: + // Interface for reporting errors. + class Reporter { + public: + virtual ~Reporter(); + + // Some corruption was detected. "size" is the approximate number + // of bytes dropped due to the corruption. + virtual void Corruption(size_t bytes, const Status& status) = 0; + }; + + // Create a reader that will return log records from "*file". + // "*file" must remain live while this Reader is in use. + // + // If "reporter" is non-NULL, it is notified whenever some data is + // dropped due to a detected corruption. "*reporter" must remain + // live while this Reader is in use. + // + // If "checksum" is true, verify checksums if available. + // + // The Reader will start reading at the first record located at physical + // position >= initial_offset within the file. + Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset); + + ~Reader(); + + // Read the next record into *record. Returns true if read + // successfully, false if we hit end of the input. May use + // "*scratch" as temporary storage. The contents filled in *record + // will only be valid until the next mutating operation on this + // reader or the next mutation to *scratch. + bool ReadRecord(Slice* record, std::string* scratch); + + // Returns the physical offset of the last record returned by ReadRecord. + // + // Undefined before the first call to ReadRecord. + uint64_t LastRecordOffset(); + + private: + SequentialFile* const file_; + Reporter* const reporter_; + bool const checksum_; + char* const backing_store_; + Slice buffer_; + bool eof_; // Last Read() indicated EOF by returning < kBlockSize + + // Offset of the last record returned by ReadRecord. + uint64_t last_record_offset_; + // Offset of the first location past the end of buffer_. + uint64_t end_of_buffer_offset_; + + // Offset at which to start looking for the first record to return + uint64_t const initial_offset_; + + // Extend record types with the following special values + enum { + kEof = kMaxRecordType + 1, + // Returned whenever we find an invalid physical record. + // Currently there are three situations in which this happens: + // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) + // * The record is a 0-length record (No drop is reported) + // * The record is below constructor's initial_offset (No drop is reported) + kBadRecord = kMaxRecordType + 2 + }; + + // Skips all blocks that are completely before "initial_offset_". + // + // Returns true on success. Handles reporting. + bool SkipToInitialBlock(); + + // Return type, or one of the preceding special values + unsigned int ReadPhysicalRecord(Slice* result); + + // Reports dropped bytes to the reporter. + // buffer_ must be updated to remove the dropped bytes prior to invocation. + void ReportCorruption(size_t bytes, const char* reason); + void ReportDrop(size_t bytes, const Status& reason); + + // No copying allowed + Reader(const Reader&); + void operator=(const Reader&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/db/log_test.cc b/db/log_test.cc new file mode 100644 index 000000000..4c5cf8757 --- /dev/null +++ b/db/log_test.cc @@ -0,0 +1,500 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { +namespace log { + +// Construct a string of the specified length made out of the supplied +// partial string. +static std::string BigString(const std::string& partial_string, size_t n) { + std::string result; + while (result.size() < n) { + result.append(partial_string); + } + result.resize(n); + return result; +} + +// Construct a string from a number +static std::string NumberString(int n) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d.", n); + return std::string(buf); +} + +// Return a skewed potentially long string +static std::string RandomSkewedString(int i, Random* rnd) { + return BigString(NumberString(i), rnd->Skewed(17)); +} + +class LogTest { + private: + class StringDest : public WritableFile { + public: + std::string contents_; + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + virtual Status Append(const Slice& slice) { + contents_.append(slice.data(), slice.size()); + return Status::OK(); + } + }; + + class StringSource : public SequentialFile { + public: + Slice contents_; + bool force_error_; + bool returned_partial_; + StringSource() : force_error_(false), returned_partial_(false) { } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error"; + + if (force_error_) { + force_error_ = false; + returned_partial_ = true; + return Status::Corruption("read error"); + } + + if (contents_.size() < n) { + n = contents_.size(); + returned_partial_ = true; + } + *result = Slice(contents_.data(), n); + contents_.remove_prefix(n); + return Status::OK(); + } + + virtual Status Skip(uint64_t n) { + if (n > contents_.size()) { + contents_.clear(); + return Status::NotFound("in-memory file skipepd past end"); + } + + contents_.remove_prefix(n); + + return Status::OK(); + } + }; + + class ReportCollector : public Reader::Reporter { + public: + size_t dropped_bytes_; + std::string message_; + + ReportCollector() : dropped_bytes_(0) { } + virtual void Corruption(size_t bytes, const Status& status) { + dropped_bytes_ += bytes; + message_.append(status.ToString()); + } + }; + + StringDest dest_; + StringSource source_; + ReportCollector report_; + bool reading_; + Writer writer_; + Reader reader_; + + // Record metadata for testing initial offset functionality + static size_t initial_offset_record_sizes_[]; + static uint64_t initial_offset_last_record_offsets_[]; + + public: + LogTest() : reading_(false), + writer_(&dest_), + reader_(&source_, &report_, true/*checksum*/, + 0/*initial_offset*/) { + } + + void Write(const std::string& msg) { + ASSERT_TRUE(!reading_) << "Write() after starting to read"; + writer_.AddRecord(Slice(msg)); + } + + size_t WrittenBytes() const { + return dest_.contents_.size(); + } + + std::string Read() { + if (!reading_) { + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + } + std::string scratch; + Slice record; + if (reader_.ReadRecord(&record, &scratch)) { + return record.ToString(); + } else { + return "EOF"; + } + } + + void IncrementByte(int offset, int delta) { + dest_.contents_[offset] += delta; + } + + void SetByte(int offset, char new_byte) { + dest_.contents_[offset] = new_byte; + } + + void ShrinkSize(int bytes) { + dest_.contents_.resize(dest_.contents_.size() - bytes); + } + + void FixChecksum(int header_offset, int len) { + // Compute crc of type/len/data + uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len); + crc = crc32c::Mask(crc); + EncodeFixed32(&dest_.contents_[header_offset], crc); + } + + void ForceError() { + source_.force_error_ = true; + } + + size_t DroppedBytes() const { + return report_.dropped_bytes_; + } + + std::string ReportMessage() const { + return report_.message_; + } + + // Returns OK iff recorded error message contains "msg" + std::string MatchError(const std::string& msg) const { + if (report_.message_.find(msg) == std::string::npos) { + return report_.message_; + } else { + return "OK"; + } + } + + void WriteInitialOffsetLog() { + for (int i = 0; i < 4; i++) { + std::string record(initial_offset_record_sizes_[i], + static_cast('a' + i)); + Write(record); + } + } + + void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + WrittenBytes() + offset_past_end); + Slice record; + std::string scratch; + ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch)); + delete offset_reader; + } + + void CheckInitialOffsetRecord(uint64_t initial_offset, + int expected_record_offset) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + initial_offset); + Slice record; + std::string scratch; + ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); + ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], + record.size()); + ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], + offset_reader->LastRecordOffset()); + ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); + delete offset_reader; + } + +}; + +size_t LogTest::initial_offset_record_sizes_[] = + {10000, // Two sizable records in first block + 10000, + 2 * log::kBlockSize - 1000, // Span three blocks + 1}; + +uint64_t LogTest::initial_offset_last_record_offsets_[] = + {0, + kHeaderSize + 10000, + 2 * (kHeaderSize + 10000), + 2 * (kHeaderSize + 10000) + + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize}; + + +TEST(LogTest, Empty) { + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, ReadWrite) { + Write("foo"); + Write("bar"); + Write(""); + Write("xxxx"); + ASSERT_EQ("foo", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("xxxx", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("EOF", Read()); // Make sure reads at eof work +} + +TEST(LogTest, ManyBlocks) { + for (int i = 0; i < 100000; i++) { + Write(NumberString(i)); + } + for (int i = 0; i < 100000; i++) { + ASSERT_EQ(NumberString(i), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, Fragmentation) { + Write("small"); + Write(BigString("medium", 50000)); + Write(BigString("large", 100000)); + ASSERT_EQ("small", Read()); + ASSERT_EQ(BigString("medium", 50000), Read()); + ASSERT_EQ(BigString("large", 100000), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer2) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, ShortTrailer) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, AlignedEof) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, RandomRead) { + const int N = 500; + Random write_rnd(301); + for (int i = 0; i < N; i++) { + Write(RandomSkewedString(i, &write_rnd)); + } + Random read_rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +// Tests of all the error paths in log_reader.cc follow: + +TEST(LogTest, ReadError) { + Write("foo"); + ForceError(); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("read error")); +} + +TEST(LogTest, BadRecordType) { + Write("foo"); + // Type is stored in header[6] + IncrementByte(6, 100); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("unknown record type")); +} + +TEST(LogTest, TruncatedTrailingRecord) { + Write("foo"); + ShrinkSize(4); // Drop all payload as well as a header byte + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kHeaderSize - 1, DroppedBytes()); + ASSERT_EQ("OK", MatchError("truncated record at end of file")); +} + +TEST(LogTest, BadLength) { + Write("foo"); + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kHeaderSize + 2, DroppedBytes()); + ASSERT_EQ("OK", MatchError("bad record length")); +} + +TEST(LogTest, ChecksumMismatch) { + Write("foo"); + IncrementByte(0, 10); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(10, DroppedBytes()); + ASSERT_EQ("OK", MatchError("checksum mismatch")); +} + +TEST(LogTest, UnexpectedMiddleType) { + Write("foo"); + SetByte(6, kMiddleType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedLastType) { + Write("foo"); + SetByte(6, kLastType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedFullType) { + Write("foo"); + Write("bar"); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, UnexpectedFirstType) { + Write("foo"); + Write(BigString("bar", 100000)); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ(BigString("bar", 100000), Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, ErrorJoinsRecords) { + // Consider two fragmented records: + // first(R1) last(R1) first(R2) last(R2) + // where the middle two fragments disappear. We do not want + // first(R1),last(R2) to get joined and returned as a valid record. + + // Write records that span two blocks + Write(BigString("foo", kBlockSize)); + Write(BigString("bar", kBlockSize)); + Write("correct"); + + // Wipe the middle block + for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) { + SetByte(offset, 'x'); + } + + ASSERT_EQ("correct", Read()); + ASSERT_EQ("EOF", Read()); + const int dropped = DroppedBytes(); + ASSERT_LE(dropped, 2*kBlockSize + 100); + ASSERT_GE(dropped, 2*kBlockSize); +} + +TEST(LogTest, ReadStart) { + CheckInitialOffsetRecord(0, 0); +} + +TEST(LogTest, ReadSecondOneOff) { + CheckInitialOffsetRecord(1, 1); +} + +TEST(LogTest, ReadSecondTenThousand) { + CheckInitialOffsetRecord(10000, 1); +} + +TEST(LogTest, ReadSecondStart) { + CheckInitialOffsetRecord(10007, 1); +} + +TEST(LogTest, ReadThirdOneOff) { + CheckInitialOffsetRecord(10008, 2); +} + +TEST(LogTest, ReadThirdStart) { + CheckInitialOffsetRecord(20014, 2); +} + +TEST(LogTest, ReadFourthOneOff) { + CheckInitialOffsetRecord(20015, 3); +} + +TEST(LogTest, ReadFourthFirstBlockTrailer) { + CheckInitialOffsetRecord(log::kBlockSize - 4, 3); +} + +TEST(LogTest, ReadFourthMiddleBlock) { + CheckInitialOffsetRecord(log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthLastBlock) { + CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthStart) { + CheckInitialOffsetRecord( + 2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, + 3); +} + +TEST(LogTest, ReadEnd) { + CheckOffsetPastEndReturnsNoRecords(0); +} + +TEST(LogTest, ReadPastEnd) { + CheckOffsetPastEndReturnsNoRecords(5); +} + +} // namespace log +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/log_writer.cc b/db/log_writer.cc new file mode 100644 index 000000000..2da99ac08 --- /dev/null +++ b/db/log_writer.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_writer.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Writer::Writer(WritableFile* dest) + : dest_(dest), + block_offset_(0) { + for (int i = 0; i <= kMaxRecordType; i++) { + char t = static_cast(i); + type_crc_[i] = crc32c::Value(&t, 1); + } +} + +Writer::~Writer() { +} + +Status Writer::AddRecord(const Slice& slice) { + const char* ptr = slice.data(); + size_t left = slice.size(); + + // Fragment the record if necessary and emit it. Note that if slice + // is empty, we still want to iterate once to emit a single + // zero-length record + Status s; + bool begin = true; + do { + const int leftover = kBlockSize - block_offset_; + assert(leftover >= 0); + if (leftover < kHeaderSize) { + // Switch to a new block + if (leftover > 0) { + // Fill the trailer (literal below relies on kHeaderSize being 7) + assert(kHeaderSize == 7); + dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); + } + block_offset_ = 0; + } + + // Invariant: we never leave < kHeaderSize bytes in a block. + assert(kBlockSize - block_offset_ - kHeaderSize >= 0); + + const size_t avail = kBlockSize - block_offset_ - kHeaderSize; + const size_t fragment_length = (left < avail) ? left : avail; + + RecordType type; + const bool end = (left == fragment_length); + if (begin && end) { + type = kFullType; + } else if (begin) { + type = kFirstType; + } else if (end) { + type = kLastType; + } else { + type = kMiddleType; + } + + s = EmitPhysicalRecord(type, ptr, fragment_length); + ptr += fragment_length; + left -= fragment_length; + begin = false; + } while (s.ok() && left > 0); + return s; +} + +Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { + assert(n <= 0xffff); // Must fit in two bytes + assert(block_offset_ + kHeaderSize + n <= kBlockSize); + + // Format the header + char buf[kHeaderSize]; + buf[4] = static_cast(n & 0xff); + buf[5] = static_cast(n >> 8); + buf[6] = static_cast(t); + + // Compute the crc of the record type and the payload. + uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); + crc = crc32c::Mask(crc); // Adjust for storage + EncodeFixed32(buf, crc); + + // Write the header and the payload + Status s = dest_->Append(Slice(buf, kHeaderSize)); + if (s.ok()) { + s = dest_->Append(Slice(ptr, n)); + if (s.ok()) { + s = dest_->Flush(); + } + } + block_offset_ += kHeaderSize + n; + return s; +} + +} // namespace log +} // namespace leveldb diff --git a/db/log_writer.h b/db/log_writer.h new file mode 100644 index 000000000..a3a954d96 --- /dev/null +++ b/db/log_writer.h @@ -0,0 +1,48 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_ +#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ + +#include +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class WritableFile; + +namespace log { + +class Writer { + public: + // Create a writer that will append data to "*dest". + // "*dest" must be initially empty. + // "*dest" must remain live while this Writer is in use. + explicit Writer(WritableFile* dest); + ~Writer(); + + Status AddRecord(const Slice& slice); + + private: + WritableFile* dest_; + int block_offset_; // Current offset in block + + // crc32c values for all supported record types. These are + // pre-computed to reduce the overhead of computing the crc of the + // record type stored in the header. + uint32_t type_crc_[kMaxRecordType + 1]; + + Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); + + // No copying allowed + Writer(const Writer&); + void operator=(const Writer&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/db/memtable.cc b/db/memtable.cc new file mode 100644 index 000000000..bfec0a7e7 --- /dev/null +++ b/db/memtable.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/memtable.h" +#include "db/dbformat.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "util/coding.h" + +namespace leveldb { + +static Slice GetLengthPrefixedSlice(const char* data) { + uint32_t len; + const char* p = data; + p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted + return Slice(p, len); +} + +MemTable::MemTable(const InternalKeyComparator& cmp) + : comparator_(cmp), + refs_(0), + table_(comparator_, &arena_) { +} + +MemTable::~MemTable() { + assert(refs_ == 0); +} + +size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } + +int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) + const { + // Internal keys are encoded as length-prefixed strings. + Slice a = GetLengthPrefixedSlice(aptr); + Slice b = GetLengthPrefixedSlice(bptr); + return comparator.Compare(a, b); +} + +// Encode a suitable internal key target for "target" and return it. +// Uses *scratch as scratch space, and the returned pointer will point +// into this scratch space. +static const char* EncodeKey(std::string* scratch, const Slice& target) { + scratch->clear(); + PutVarint32(scratch, target.size()); + scratch->append(target.data(), target.size()); + return scratch->data(); +} + +class MemTableIterator: public Iterator { + public: + explicit MemTableIterator(MemTable::Table* table) : iter_(table) { } + + virtual bool Valid() const { return iter_.Valid(); } + virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } + virtual void SeekToFirst() { iter_.SeekToFirst(); } + virtual void SeekToLast() { iter_.SeekToLast(); } + virtual void Next() { iter_.Next(); } + virtual void Prev() { iter_.Prev(); } + virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } + virtual Slice value() const { + Slice key_slice = GetLengthPrefixedSlice(iter_.key()); + return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); + } + + virtual Status status() const { return Status::OK(); } + + private: + MemTable::Table::Iterator iter_; + std::string tmp_; // For passing to EncodeKey + + // No copying allowed + MemTableIterator(const MemTableIterator&); + void operator=(const MemTableIterator&); +}; + +Iterator* MemTable::NewIterator() { + return new MemTableIterator(&table_); +} + +void MemTable::Add(SequenceNumber s, ValueType type, + const Slice& key, + const Slice& value) { + // Format of an entry is concatenation of: + // key_size : varint32 of internal_key.size() + // key bytes : char[internal_key.size()] + // value_size : varint32 of value.size() + // value bytes : char[value.size()] + size_t key_size = key.size(); + size_t val_size = value.size(); + size_t internal_key_size = key_size + 8; + const size_t encoded_len = + VarintLength(internal_key_size) + internal_key_size + + VarintLength(val_size) + val_size; + char* buf = arena_.Allocate(encoded_len); + char* p = EncodeVarint32(buf, internal_key_size); + memcpy(p, key.data(), key_size); + p += key_size; + EncodeFixed64(p, (s << 8) | type); + p += 8; + p = EncodeVarint32(p, val_size); + memcpy(p, value.data(), val_size); + assert((p + val_size) - buf == encoded_len); + table_.Insert(buf); +} + +bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { + Slice memkey = key.memtable_key(); + Table::Iterator iter(&table_); + iter.Seek(memkey.data()); + if (iter.Valid()) { + // entry format is: + // klength varint32 + // userkey char[klength] + // tag uint64 + // vlength varint32 + // value char[vlength] + // Check that it belongs to same user key. We do not check the + // sequence number since the Seek() call above should have skipped + // all entries with overly large sequence numbers. + const char* entry = iter.key(); + uint32_t key_length; + const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); + if (comparator_.comparator.user_comparator()->Compare( + Slice(key_ptr, key_length - 8), + key.user_key()) == 0) { + // Correct user key + const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); + switch (static_cast(tag & 0xff)) { + case kTypeValue: { + Slice v = GetLengthPrefixedSlice(key_ptr + key_length); + value->assign(v.data(), v.size()); + return true; + } + case kTypeDeletion: + *s = Status::NotFound(Slice()); + return true; + } + } + } + return false; +} + +} // namespace leveldb diff --git a/db/memtable.h b/db/memtable.h new file mode 100644 index 000000000..92e90bb09 --- /dev/null +++ b/db/memtable.h @@ -0,0 +1,91 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_ +#define STORAGE_LEVELDB_DB_MEMTABLE_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/skiplist.h" +#include "util/arena.h" + +namespace leveldb { + +class InternalKeyComparator; +class Mutex; +class MemTableIterator; + +class MemTable { + public: + // MemTables are reference counted. The initial reference count + // is zero and the caller must call Ref() at least once. + explicit MemTable(const InternalKeyComparator& comparator); + + // Increase reference count. + void Ref() { ++refs_; } + + // Drop reference count. Delete if no more references exist. + void Unref() { + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + delete this; + } + } + + // Returns an estimate of the number of bytes of data in use by this + // data structure. + // + // REQUIRES: external synchronization to prevent simultaneous + // operations on the same MemTable. + size_t ApproximateMemoryUsage(); + + // Return an iterator that yields the contents of the memtable. + // + // The caller must ensure that the underlying MemTable remains live + // while the returned iterator is live. The keys returned by this + // iterator are internal keys encoded by AppendInternalKey in the + // db/format.{h,cc} module. + Iterator* NewIterator(); + + // Add an entry into memtable that maps key to value at the + // specified sequence number and with the specified type. + // Typically value will be empty if type==kTypeDeletion. + void Add(SequenceNumber seq, ValueType type, + const Slice& key, + const Slice& value); + + // If memtable contains a value for key, store it in *value and return true. + // If memtable contains a deletion for key, store a NotFound() error + // in *status and return true. + // Else, return false. + bool Get(const LookupKey& key, std::string* value, Status* s); + + private: + ~MemTable(); // Private since only Unref() should be used to delete it + + struct KeyComparator { + const InternalKeyComparator comparator; + explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { } + int operator()(const char* a, const char* b) const; + }; + friend class MemTableIterator; + friend class MemTableBackwardIterator; + + typedef SkipList Table; + + KeyComparator comparator_; + int refs_; + Arena arena_; + Table table_; + + // No copying allowed + MemTable(const MemTable&); + void operator=(const MemTable&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/db/repair.cc b/db/repair.cc new file mode 100644 index 000000000..022d52f3d --- /dev/null +++ b/db/repair.cc @@ -0,0 +1,389 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// We recover the contents of the descriptor from the other files we find. +// (1) Any log files are first converted to tables +// (2) We scan every table to compute +// (a) smallest/largest for the table +// (b) largest sequence number in the table +// (3) We generate descriptor contents: +// - log number is set to zero +// - next-file-number is set to 1 + largest file number we found +// - last-sequence-number is set to largest sequence# found across +// all tables (see 2c) +// - compaction pointers are cleared +// - every table file is added at level 0 +// +// Possible optimization 1: +// (a) Compute total size and use to pick appropriate max-level M +// (b) Sort tables by largest sequence# in the table +// (c) For each table: if it overlaps earlier table, place in level-0, +// else place in level-M. +// Possible optimization 2: +// Store per-table metadata (smallest, largest, largest-seq#, ...) +// in the table's meta section to speed up ScanTable. + +#include "db/builder.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" + +namespace leveldb { + +namespace { + +class Repairer { + public: + Repairer(const std::string& dbname, const Options& options) + : dbname_(dbname), + env_(options.env), + icmp_(options.comparator), + ipolicy_(options.filter_policy), + options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), + owns_info_log_(options_.info_log != options.info_log), + owns_cache_(options_.block_cache != options.block_cache), + next_file_number_(1) { + // TableCache can be small since we expect each table to be opened once. + table_cache_ = new TableCache(dbname_, &options_, 10); + } + + ~Repairer() { + delete table_cache_; + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } + } + + Status Run() { + Status status = FindFiles(); + if (status.ok()) { + ConvertLogFilesToTables(); + ExtractMetaData(); + status = WriteDescriptor(); + } + if (status.ok()) { + unsigned long long bytes = 0; + for (size_t i = 0; i < tables_.size(); i++) { + bytes += tables_[i].meta.file_size; + } + Log(options_.info_log, + "**** Repaired leveldb %s; " + "recovered %d files; %llu bytes. " + "Some data may have been lost. " + "****", + dbname_.c_str(), + static_cast(tables_.size()), + bytes); + } + return status; + } + + private: + struct TableInfo { + FileMetaData meta; + SequenceNumber max_sequence; + }; + + std::string const dbname_; + Env* const env_; + InternalKeyComparator const icmp_; + InternalFilterPolicy const ipolicy_; + Options const options_; + bool owns_info_log_; + bool owns_cache_; + TableCache* table_cache_; + VersionEdit edit_; + + std::vector manifests_; + std::vector table_numbers_; + std::vector logs_; + std::vector tables_; + uint64_t next_file_number_; + + Status FindFiles() { + std::vector filenames; + Status status = env_->GetChildren(dbname_, &filenames); + if (!status.ok()) { + return status; + } + if (filenames.empty()) { + return Status::IOError(dbname_, "repair found no files"); + } + + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + if (type == kDescriptorFile) { + manifests_.push_back(filenames[i]); + } else { + if (number + 1 > next_file_number_) { + next_file_number_ = number + 1; + } + if (type == kLogFile) { + logs_.push_back(number); + } else if (type == kTableFile) { + table_numbers_.push_back(number); + } else { + // Ignore other files + } + } + } + } + return status; + } + + void ConvertLogFilesToTables() { + for (size_t i = 0; i < logs_.size(); i++) { + std::string logname = LogFileName(dbname_, logs_[i]); + Status status = ConvertLogToTable(logs_[i]); + if (!status.ok()) { + Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", + (unsigned long long) logs_[i], + status.ToString().c_str()); + } + ArchiveFile(logname); + } + } + + Status ConvertLogToTable(uint64_t log) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + uint64_t lognum; + virtual void Corruption(size_t bytes, const Status& s) { + // We print error messages for corruption, but continue repairing. + Log(info_log, "Log #%llu: dropping %d bytes; %s", + (unsigned long long) lognum, + static_cast(bytes), + s.ToString().c_str()); + } + }; + + // Open the log file + std::string logname = LogFileName(dbname_, log); + SequentialFile* lfile; + Status status = env_->NewSequentialFile(logname, &lfile); + if (!status.ok()) { + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.lognum = log; + // We intentially make log::Reader do checksumming so that + // corruptions cause entire commits to be skipped instead of + // propagating bad information (like overly large sequence + // numbers). + log::Reader reader(lfile, &reporter, false/*do not checksum*/, + 0/*initial_offset*/); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = new MemTable(icmp_); + mem->Ref(); + int counter = 0; + while (reader.ReadRecord(&record, &scratch)) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small")); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + status = WriteBatchInternal::InsertInto(&batch, mem); + if (status.ok()) { + counter += WriteBatchInternal::Count(&batch); + } else { + Log(options_.info_log, "Log #%llu: ignoring %s", + (unsigned long long) log, + status.ToString().c_str()); + status = Status::OK(); // Keep going with rest of file + } + } + delete lfile; + + // Do not record a version edit for this conversion to a Table + // since ExtractMetaData() will also generate edits. + FileMetaData meta; + meta.number = next_file_number_++; + Iterator* iter = mem->NewIterator(); + status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + delete iter; + mem->Unref(); + mem = NULL; + if (status.ok()) { + if (meta.file_size > 0) { + table_numbers_.push_back(meta.number); + } + } + Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", + (unsigned long long) log, + counter, + (unsigned long long) meta.number, + status.ToString().c_str()); + return status; + } + + void ExtractMetaData() { + std::vector kept; + for (size_t i = 0; i < table_numbers_.size(); i++) { + TableInfo t; + t.meta.number = table_numbers_[i]; + Status status = ScanTable(&t); + if (!status.ok()) { + std::string fname = TableFileName(dbname_, table_numbers_[i]); + Log(options_.info_log, "Table #%llu: ignoring %s", + (unsigned long long) table_numbers_[i], + status.ToString().c_str()); + ArchiveFile(fname); + } else { + tables_.push_back(t); + } + } + } + + Status ScanTable(TableInfo* t) { + std::string fname = TableFileName(dbname_, t->meta.number); + int counter = 0; + Status status = env_->GetFileSize(fname, &t->meta.file_size); + if (status.ok()) { + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), t->meta.number, t->meta.file_size); + bool empty = true; + ParsedInternalKey parsed; + t->max_sequence = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + Slice key = iter->key(); + if (!ParseInternalKey(key, &parsed)) { + Log(options_.info_log, "Table #%llu: unparsable key %s", + (unsigned long long) t->meta.number, + EscapeString(key).c_str()); + continue; + } + + counter++; + if (empty) { + empty = false; + t->meta.smallest.DecodeFrom(key); + } + t->meta.largest.DecodeFrom(key); + if (parsed.sequence > t->max_sequence) { + t->max_sequence = parsed.sequence; + } + } + if (!iter->status().ok()) { + status = iter->status(); + } + delete iter; + } + Log(options_.info_log, "Table #%llu: %d entries %s", + (unsigned long long) t->meta.number, + counter, + status.ToString().c_str()); + return status; + } + + Status WriteDescriptor() { + std::string tmp = TempFileName(dbname_, 1); + WritableFile* file; + Status status = env_->NewWritableFile(tmp, &file); + if (!status.ok()) { + return status; + } + + SequenceNumber max_sequence = 0; + for (size_t i = 0; i < tables_.size(); i++) { + if (max_sequence < tables_[i].max_sequence) { + max_sequence = tables_[i].max_sequence; + } + } + + edit_.SetComparatorName(icmp_.user_comparator()->Name()); + edit_.SetLogNumber(0); + edit_.SetNextFile(next_file_number_); + edit_.SetLastSequence(max_sequence); + + for (size_t i = 0; i < tables_.size(); i++) { + // TODO(opt): separate out into multiple levels + const TableInfo& t = tables_[i]; + edit_.AddFile(0, t.meta.number, t.meta.file_size, + t.meta.smallest, t.meta.largest); + } + + //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); + { + log::Writer log(file); + std::string record; + edit_.EncodeTo(&record); + status = log.AddRecord(record); + } + if (status.ok()) { + status = file->Close(); + } + delete file; + file = NULL; + + if (!status.ok()) { + env_->DeleteFile(tmp); + } else { + // Discard older manifests + for (size_t i = 0; i < manifests_.size(); i++) { + ArchiveFile(dbname_ + "/" + manifests_[i]); + } + + // Install new manifest + status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); + if (status.ok()) { + status = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(tmp); + } + } + return status; + } + + void ArchiveFile(const std::string& fname) { + // Move into another directory. E.g., for + // dir/foo + // rename to + // dir/lost/foo + const char* slash = strrchr(fname.c_str(), '/'); + std::string new_dir; + if (slash != NULL) { + new_dir.assign(fname.data(), slash - fname.data()); + } + new_dir.append("/lost"); + env_->CreateDir(new_dir); // Ignore error + std::string new_file = new_dir; + new_file.append("/"); + new_file.append((slash == NULL) ? fname.c_str() : slash + 1); + Status s = env_->RenameFile(fname, new_file); + Log(options_.info_log, "Archiving %s: %s\n", + fname.c_str(), s.ToString().c_str()); + } +}; +} // namespace + +Status RepairDB(const std::string& dbname, const Options& options) { + Repairer repairer(dbname, options); + return repairer.Run(); +} + +} // namespace leveldb diff --git a/db/skiplist.h b/db/skiplist.h new file mode 100644 index 000000000..af85be6d0 --- /dev/null +++ b/db/skiplist.h @@ -0,0 +1,379 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Thread safety +// ------------- +// +// Writes require external synchronization, most likely a mutex. +// Reads require a guarantee that the SkipList will not be destroyed +// while the read is in progress. Apart from that, reads progress +// without any internal locking or synchronization. +// +// Invariants: +// +// (1) Allocated nodes are never deleted until the SkipList is +// destroyed. This is trivially guaranteed by the code since we +// never delete any skip list nodes. +// +// (2) The contents of a Node except for the next/prev pointers are +// immutable after the Node has been linked into the SkipList. +// Only Insert() modifies the list, and it is careful to initialize +// a node and use release-stores to publish the nodes in one or +// more lists. +// +// ... prev vs. next pointer ordering ... + +#include +#include +#include "port/port.h" +#include "util/arena.h" +#include "util/random.h" + +namespace leveldb { + +class Arena; + +template +class SkipList { + private: + struct Node; + + public: + // Create a new SkipList object that will use "cmp" for comparing keys, + // and will allocate memory using "*arena". Objects allocated in the arena + // must remain allocated for the lifetime of the skiplist object. + explicit SkipList(Comparator cmp, Arena* arena); + + // Insert key into the list. + // REQUIRES: nothing that compares equal to key is currently in the list. + void Insert(const Key& key); + + // Returns true iff an entry that compares equal to key is in the list. + bool Contains(const Key& key) const; + + // Iteration over the contents of a skip list + class Iterator { + public: + // Initialize an iterator over the specified list. + // The returned iterator is not valid. + explicit Iterator(const SkipList* list); + + // Returns true iff the iterator is positioned at a valid node. + bool Valid() const; + + // Returns the key at the current position. + // REQUIRES: Valid() + const Key& key() const; + + // Advances to the next position. + // REQUIRES: Valid() + void Next(); + + // Advances to the previous position. + // REQUIRES: Valid() + void Prev(); + + // Advance to the first entry with a key >= target + void Seek(const Key& target); + + // Position at the first entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToFirst(); + + // Position at the last entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToLast(); + + private: + const SkipList* list_; + Node* node_; + // Intentionally copyable + }; + + private: + enum { kMaxHeight = 12 }; + + // Immutable after construction + Comparator const compare_; + Arena* const arena_; // Arena used for allocations of nodes + + Node* const head_; + + // Modified only by Insert(). Read racily by readers, but stale + // values are ok. + port::AtomicPointer max_height_; // Height of the entire list + + inline int GetMaxHeight() const { + return static_cast( + reinterpret_cast(max_height_.NoBarrier_Load())); + } + + // Read/written only by Insert(). + Random rnd_; + + Node* NewNode(const Key& key, int height); + int RandomHeight(); + bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } + + // Return true if key is greater than the data stored in "n" + bool KeyIsAfterNode(const Key& key, Node* n) const; + + // Return the earliest node that comes at or after key. + // Return NULL if there is no such node. + // + // If prev is non-NULL, fills prev[level] with pointer to previous + // node at "level" for every level in [0..max_height_-1]. + Node* FindGreaterOrEqual(const Key& key, Node** prev) const; + + // Return the latest node with a key < key. + // Return head_ if there is no such node. + Node* FindLessThan(const Key& key) const; + + // Return the last node in the list. + // Return head_ if list is empty. + Node* FindLast() const; + + // No copying allowed + SkipList(const SkipList&); + void operator=(const SkipList&); +}; + +// Implementation details follow +template +struct SkipList::Node { + explicit Node(const Key& k) : key(k) { } + + Key const key; + + // Accessors/mutators for links. Wrapped in methods so we can + // add the appropriate barriers as necessary. + Node* Next(int n) { + assert(n >= 0); + // Use an 'acquire load' so that we observe a fully initialized + // version of the returned Node. + return reinterpret_cast(next_[n].Acquire_Load()); + } + void SetNext(int n, Node* x) { + assert(n >= 0); + // Use a 'release store' so that anybody who reads through this + // pointer observes a fully initialized version of the inserted node. + next_[n].Release_Store(x); + } + + // No-barrier variants that can be safely used in a few locations. + Node* NoBarrier_Next(int n) { + assert(n >= 0); + return reinterpret_cast(next_[n].NoBarrier_Load()); + } + void NoBarrier_SetNext(int n, Node* x) { + assert(n >= 0); + next_[n].NoBarrier_Store(x); + } + + private: + // Array of length equal to the node height. next_[0] is lowest level link. + port::AtomicPointer next_[1]; +}; + +template +typename SkipList::Node* +SkipList::NewNode(const Key& key, int height) { + char* mem = arena_->AllocateAligned( + sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); + return new (mem) Node(key); +} + +template +inline SkipList::Iterator::Iterator(const SkipList* list) { + list_ = list; + node_ = NULL; +} + +template +inline bool SkipList::Iterator::Valid() const { + return node_ != NULL; +} + +template +inline const Key& SkipList::Iterator::key() const { + assert(Valid()); + return node_->key; +} + +template +inline void SkipList::Iterator::Next() { + assert(Valid()); + node_ = node_->Next(0); +} + +template +inline void SkipList::Iterator::Prev() { + // Instead of using explicit "prev" links, we just search for the + // last node that falls before key. + assert(Valid()); + node_ = list_->FindLessThan(node_->key); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +inline void SkipList::Iterator::Seek(const Key& target) { + node_ = list_->FindGreaterOrEqual(target, NULL); +} + +template +inline void SkipList::Iterator::SeekToFirst() { + node_ = list_->head_->Next(0); +} + +template +inline void SkipList::Iterator::SeekToLast() { + node_ = list_->FindLast(); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +int SkipList::RandomHeight() { + // Increase height with probability 1 in kBranching + static const unsigned int kBranching = 4; + int height = 1; + while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { + height++; + } + assert(height > 0); + assert(height <= kMaxHeight); + return height; +} + +template +bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { + // NULL n is considered infinite + return (n != NULL) && (compare_(n->key, key) < 0); +} + +template +typename SkipList::Node* SkipList::FindGreaterOrEqual(const Key& key, Node** prev) + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (KeyIsAfterNode(key, next)) { + // Keep searching in this list + x = next; + } else { + if (prev != NULL) prev[level] = x; + if (level == 0) { + return next; + } else { + // Switch to next list + level--; + } + } + } +} + +template +typename SkipList::Node* +SkipList::FindLessThan(const Key& key) const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + assert(x == head_ || compare_(x->key, key) < 0); + Node* next = x->Next(level); + if (next == NULL || compare_(next->key, key) >= 0) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +typename SkipList::Node* SkipList::FindLast() + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (next == NULL) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +SkipList::SkipList(Comparator cmp, Arena* arena) + : compare_(cmp), + arena_(arena), + head_(NewNode(0 /* any key will do */, kMaxHeight)), + max_height_(reinterpret_cast(1)), + rnd_(0xdeadbeef) { + for (int i = 0; i < kMaxHeight; i++) { + head_->SetNext(i, NULL); + } +} + +template +void SkipList::Insert(const Key& key) { + // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() + // here since Insert() is externally synchronized. + Node* prev[kMaxHeight]; + Node* x = FindGreaterOrEqual(key, prev); + + // Our data structure does not allow duplicate insertion + assert(x == NULL || !Equal(key, x->key)); + + int height = RandomHeight(); + if (height > GetMaxHeight()) { + for (int i = GetMaxHeight(); i < height; i++) { + prev[i] = head_; + } + //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); + + // It is ok to mutate max_height_ without any synchronization + // with concurrent readers. A concurrent reader that observes + // the new value of max_height_ will see either the old value of + // new level pointers from head_ (NULL), or a new value set in + // the loop below. In the former case the reader will + // immediately drop to the next level since NULL sorts after all + // keys. In the latter case the reader will use the new node. + max_height_.NoBarrier_Store(reinterpret_cast(height)); + } + + x = NewNode(key, height); + for (int i = 0; i < height; i++) { + // NoBarrier_SetNext() suffices since we will add a barrier when + // we publish a pointer to "x" in prev[i]. + x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); + prev[i]->SetNext(i, x); + } +} + +template +bool SkipList::Contains(const Key& key) const { + Node* x = FindGreaterOrEqual(key, NULL); + if (x != NULL && Equal(key, x->key)) { + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/db/skiplist_test.cc b/db/skiplist_test.cc new file mode 100644 index 000000000..c78f4b4fb --- /dev/null +++ b/db/skiplist_test.cc @@ -0,0 +1,378 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/skiplist.h" +#include +#include "leveldb/env.h" +#include "util/arena.h" +#include "util/hash.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +typedef uint64_t Key; + +struct Comparator { + int operator()(const Key& a, const Key& b) const { + if (a < b) { + return -1; + } else if (a > b) { + return +1; + } else { + return 0; + } + } +}; + +class SkipTest { }; + +TEST(SkipTest, Empty) { + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + ASSERT_TRUE(!list.Contains(10)); + + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToFirst(); + ASSERT_TRUE(!iter.Valid()); + iter.Seek(100); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToLast(); + ASSERT_TRUE(!iter.Valid()); +} + +TEST(SkipTest, InsertAndLookup) { + const int N = 2000; + const int R = 5000; + Random rnd(1000); + std::set keys; + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + for (int i = 0; i < N; i++) { + Key key = rnd.Next() % R; + if (keys.insert(key).second) { + list.Insert(key); + } + } + + for (int i = 0; i < R; i++) { + if (list.Contains(i)) { + ASSERT_EQ(keys.count(i), 1); + } else { + ASSERT_EQ(keys.count(i), 0); + } + } + + // Simple iterator tests + { + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + + iter.Seek(0); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToFirst(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToLast(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.rbegin()), iter.key()); + } + + // Forward iteration test + for (int i = 0; i < R; i++) { + SkipList::Iterator iter(&list); + iter.Seek(i); + + // Compare against model iterator + std::set::iterator model_iter = keys.lower_bound(i); + for (int j = 0; j < 3; j++) { + if (model_iter == keys.end()) { + ASSERT_TRUE(!iter.Valid()); + break; + } else { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + ++model_iter; + iter.Next(); + } + } + } + + // Backward iteration test + { + SkipList::Iterator iter(&list); + iter.SeekToLast(); + + // Compare against model iterator + for (std::set::reverse_iterator model_iter = keys.rbegin(); + model_iter != keys.rend(); + ++model_iter) { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + iter.Prev(); + } + ASSERT_TRUE(!iter.Valid()); + } +} + +// We want to make sure that with a single writer and multiple +// concurrent readers (with no synchronization other than when a +// reader's iterator is created), the reader always observes all the +// data that was present in the skip list when the iterator was +// constructor. Because insertions are happening concurrently, we may +// also observe new values that were inserted since the iterator was +// constructed, but we should never miss any values that were present +// at iterator construction time. +// +// We generate multi-part keys: +// +// where: +// key is in range [0..K-1] +// gen is a generation number for key +// hash is hash(key,gen) +// +// The insertion code picks a random key, sets gen to be 1 + the last +// generation number inserted for that key, and sets hash to Hash(key,gen). +// +// At the beginning of a read, we snapshot the last inserted +// generation number for each key. We then iterate, including random +// calls to Next() and Seek(). For every key we encounter, we +// check that it is either expected given the initial snapshot or has +// been concurrently added since the iterator started. +class ConcurrentTest { + private: + static const uint32_t K = 4; + + static uint64_t key(Key key) { return (key >> 40); } + static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; } + static uint64_t hash(Key key) { return key & 0xff; } + + static uint64_t HashNumbers(uint64_t k, uint64_t g) { + uint64_t data[2] = { k, g }; + return Hash(reinterpret_cast(data), sizeof(data), 0); + } + + static Key MakeKey(uint64_t k, uint64_t g) { + assert(sizeof(Key) == sizeof(uint64_t)); + assert(k <= K); // We sometimes pass K to seek to the end of the skiplist + assert(g <= 0xffffffffu); + return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff)); + } + + static bool IsValidKey(Key k) { + return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff); + } + + static Key RandomTarget(Random* rnd) { + switch (rnd->Next() % 10) { + case 0: + // Seek to beginning + return MakeKey(0, 0); + case 1: + // Seek to end + return MakeKey(K, 0); + default: + // Seek to middle + return MakeKey(rnd->Next() % K, 0); + } + } + + // Per-key generation + struct State { + port::AtomicPointer generation[K]; + void Set(int k, intptr_t v) { + generation[k].Release_Store(reinterpret_cast(v)); + } + intptr_t Get(int k) { + return reinterpret_cast(generation[k].Acquire_Load()); + } + + State() { + for (int k = 0; k < K; k++) { + Set(k, 0); + } + } + }; + + // Current state of the test + State current_; + + Arena arena_; + + // SkipList is not protected by mu_. We just use a single writer + // thread to modify it. + SkipList list_; + + public: + ConcurrentTest() : list_(Comparator(), &arena_) { } + + // REQUIRES: External synchronization + void WriteStep(Random* rnd) { + const uint32_t k = rnd->Next() % K; + const intptr_t g = current_.Get(k) + 1; + const Key key = MakeKey(k, g); + list_.Insert(key); + current_.Set(k, g); + } + + void ReadStep(Random* rnd) { + // Remember the initial committed state of the skiplist. + State initial_state; + for (int k = 0; k < K; k++) { + initial_state.Set(k, current_.Get(k)); + } + + Key pos = RandomTarget(rnd); + SkipList::Iterator iter(&list_); + iter.Seek(pos); + while (true) { + Key current; + if (!iter.Valid()) { + current = MakeKey(K, 0); + } else { + current = iter.key(); + ASSERT_TRUE(IsValidKey(current)) << current; + } + ASSERT_LE(pos, current) << "should not go backwards"; + + // Verify that everything in [pos,current) was not present in + // initial_state. + while (pos < current) { + ASSERT_LT(key(pos), K) << pos; + + // Note that generation 0 is never inserted, so it is ok if + // <*,0,*> is missing. + ASSERT_TRUE((gen(pos) == 0) || + (gen(pos) > initial_state.Get(key(pos))) + ) << "key: " << key(pos) + << "; gen: " << gen(pos) + << "; initgen: " + << initial_state.Get(key(pos)); + + // Advance to next key in the valid key space + if (key(pos) < key(current)) { + pos = MakeKey(key(pos) + 1, 0); + } else { + pos = MakeKey(key(pos), gen(pos) + 1); + } + } + + if (!iter.Valid()) { + break; + } + + if (rnd->Next() % 2) { + iter.Next(); + pos = MakeKey(key(pos), gen(pos) + 1); + } else { + Key new_target = RandomTarget(rnd); + if (new_target > pos) { + pos = new_target; + iter.Seek(new_target); + } + } + } + } +}; +const uint32_t ConcurrentTest::K; + +// Simple test that does single-threaded testing of the ConcurrentTest +// scaffolding. +TEST(SkipTest, ConcurrentWithoutThreads) { + ConcurrentTest test; + Random rnd(test::RandomSeed()); + for (int i = 0; i < 10000; i++) { + test.ReadStep(&rnd); + test.WriteStep(&rnd); + } +} + +class TestState { + public: + ConcurrentTest t_; + int seed_; + port::AtomicPointer quit_flag_; + + enum ReaderState { + STARTING, + RUNNING, + DONE + }; + + explicit TestState(int s) + : seed_(s), + quit_flag_(NULL), + state_(STARTING), + state_cv_(&mu_) {} + + void Wait(ReaderState s) { + mu_.Lock(); + while (state_ != s) { + state_cv_.Wait(); + } + mu_.Unlock(); + } + + void Change(ReaderState s) { + mu_.Lock(); + state_ = s; + state_cv_.Signal(); + mu_.Unlock(); + } + + private: + port::Mutex mu_; + ReaderState state_; + port::CondVar state_cv_; +}; + +static void ConcurrentReader(void* arg) { + TestState* state = reinterpret_cast(arg); + Random rnd(state->seed_); + int64_t reads = 0; + state->Change(TestState::RUNNING); + while (!state->quit_flag_.Acquire_Load()) { + state->t_.ReadStep(&rnd); + ++reads; + } + state->Change(TestState::DONE); +} + +static void RunConcurrent(int run) { + const int seed = test::RandomSeed() + (run * 100); + Random rnd(seed); + const int N = 1000; + const int kSize = 1000; + for (int i = 0; i < N; i++) { + if ((i % 100) == 0) { + fprintf(stderr, "Run %d of %d\n", i, N); + } + TestState state(seed + 1); + Env::Default()->Schedule(ConcurrentReader, &state); + state.Wait(TestState::RUNNING); + for (int i = 0; i < kSize; i++) { + state.t_.WriteStep(&rnd); + } + state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do + state.Wait(TestState::DONE); + } +} + +TEST(SkipTest, Concurrent1) { RunConcurrent(1); } +TEST(SkipTest, Concurrent2) { RunConcurrent(2); } +TEST(SkipTest, Concurrent3) { RunConcurrent(3); } +TEST(SkipTest, Concurrent4) { RunConcurrent(4); } +TEST(SkipTest, Concurrent5) { RunConcurrent(5); } + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/snapshot.h b/db/snapshot.h new file mode 100644 index 000000000..e7f8fd2c3 --- /dev/null +++ b/db/snapshot.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ +#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ + +#include "leveldb/db.h" + +namespace leveldb { + +class SnapshotList; + +// Snapshots are kept in a doubly-linked list in the DB. +// Each SnapshotImpl corresponds to a particular sequence number. +class SnapshotImpl : public Snapshot { + public: + SequenceNumber number_; // const after creation + + private: + friend class SnapshotList; + + // SnapshotImpl is kept in a doubly-linked circular list + SnapshotImpl* prev_; + SnapshotImpl* next_; + + SnapshotList* list_; // just for sanity checks +}; + +class SnapshotList { + public: + SnapshotList() { + list_.prev_ = &list_; + list_.next_ = &list_; + } + + bool empty() const { return list_.next_ == &list_; } + SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } + SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } + + const SnapshotImpl* New(SequenceNumber seq) { + SnapshotImpl* s = new SnapshotImpl; + s->number_ = seq; + s->list_ = this; + s->next_ = &list_; + s->prev_ = list_.prev_; + s->prev_->next_ = s; + s->next_->prev_ = s; + return s; + } + + void Delete(const SnapshotImpl* s) { + assert(s->list_ == this); + s->prev_->next_ = s->next_; + s->next_->prev_ = s->prev_; + delete s; + } + + private: + // Dummy head of doubly-linked list of snapshots + SnapshotImpl list_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/db/table_cache.cc b/db/table_cache.cc new file mode 100644 index 000000000..497db2707 --- /dev/null +++ b/db/table_cache.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/table_cache.h" + +#include "db/filename.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/coding.h" + +namespace leveldb { + +struct TableAndFile { + RandomAccessFile* file; + Table* table; +}; + +static void DeleteEntry(const Slice& key, void* value) { + TableAndFile* tf = reinterpret_cast(value); + delete tf->table; + delete tf->file; + delete tf; +} + +static void UnrefEntry(void* arg1, void* arg2) { + Cache* cache = reinterpret_cast(arg1); + Cache::Handle* h = reinterpret_cast(arg2); + cache->Release(h); +} + +TableCache::TableCache(const std::string& dbname, + const Options* options, + int entries) + : env_(options->env), + dbname_(dbname), + options_(options), + cache_(NewLRUCache(entries)) { +} + +TableCache::~TableCache() { + delete cache_; +} + +Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, + Cache::Handle** handle) { + Status s; + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + Slice key(buf, sizeof(buf)); + *handle = cache_->Lookup(key); + if (*handle == NULL) { + std::string fname = TableFileName(dbname_, file_number); + RandomAccessFile* file = NULL; + Table* table = NULL; + s = env_->NewRandomAccessFile(fname, &file); + if (s.ok()) { + s = Table::Open(*options_, file, file_size, &table); + } + + if (!s.ok()) { + assert(table == NULL); + delete file; + // We do not cache error results so that if the error is transient, + // or somebody repairs the file, we recover automatically. + } else { + TableAndFile* tf = new TableAndFile; + tf->file = file; + tf->table = table; + *handle = cache_->Insert(key, tf, 1, &DeleteEntry); + } + } + return s; +} + +Iterator* TableCache::NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr) { + if (tableptr != NULL) { + *tableptr = NULL; + } + + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (!s.ok()) { + return NewErrorIterator(s); + } + + Table* table = reinterpret_cast(cache_->Value(handle))->table; + Iterator* result = table->NewIterator(options); + result->RegisterCleanup(&UnrefEntry, cache_, handle); + if (tableptr != NULL) { + *tableptr = table; + } + return result; +} + +Status TableCache::Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (s.ok()) { + Table* t = reinterpret_cast(cache_->Value(handle))->table; + s = t->InternalGet(options, k, arg, saver); + cache_->Release(handle); + } + return s; +} + +void TableCache::Evict(uint64_t file_number) { + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + cache_->Erase(Slice(buf, sizeof(buf))); +} + +} // namespace leveldb diff --git a/db/table_cache.h b/db/table_cache.h new file mode 100644 index 000000000..8cf4aaf12 --- /dev/null +++ b/db/table_cache.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Thread-safe (provides internal synchronization) + +#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ +#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ + +#include +#include +#include "db/dbformat.h" +#include "leveldb/cache.h" +#include "leveldb/table.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +class TableCache { + public: + TableCache(const std::string& dbname, const Options* options, int entries); + ~TableCache(); + + // Return an iterator for the specified file number (the corresponding + // file length must be exactly "file_size" bytes). If "tableptr" is + // non-NULL, also sets "*tableptr" to point to the Table object + // underlying the returned iterator, or NULL if no Table object underlies + // the returned iterator. The returned "*tableptr" object is owned by + // the cache and should not be deleted, and is valid for as long as the + // returned iterator is live. + Iterator* NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr = NULL); + + // If a seek to internal key "k" in specified file finds an entry, + // call (*handle_result)(arg, found_key, found_value). + Status Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*handle_result)(void*, const Slice&, const Slice&)); + + // Evict any entry for the specified file number + void Evict(uint64_t file_number); + + private: + Env* const env_; + const std::string dbname_; + const Options* options_; + Cache* cache_; + + Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/db/version_edit.cc b/db/version_edit.cc new file mode 100644 index 000000000..f10a2d58b --- /dev/null +++ b/db/version_edit.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" + +#include "db/version_set.h" +#include "util/coding.h" + +namespace leveldb { + +// Tag numbers for serialized VersionEdit. These numbers are written to +// disk and should not be changed. +enum Tag { + kComparator = 1, + kLogNumber = 2, + kNextFileNumber = 3, + kLastSequence = 4, + kCompactPointer = 5, + kDeletedFile = 6, + kNewFile = 7, + // 8 was used for large value refs + kPrevLogNumber = 9 +}; + +void VersionEdit::Clear() { + comparator_.clear(); + log_number_ = 0; + prev_log_number_ = 0; + last_sequence_ = 0; + next_file_number_ = 0; + has_comparator_ = false; + has_log_number_ = false; + has_prev_log_number_ = false; + has_next_file_number_ = false; + has_last_sequence_ = false; + deleted_files_.clear(); + new_files_.clear(); +} + +void VersionEdit::EncodeTo(std::string* dst) const { + if (has_comparator_) { + PutVarint32(dst, kComparator); + PutLengthPrefixedSlice(dst, comparator_); + } + if (has_log_number_) { + PutVarint32(dst, kLogNumber); + PutVarint64(dst, log_number_); + } + if (has_prev_log_number_) { + PutVarint32(dst, kPrevLogNumber); + PutVarint64(dst, prev_log_number_); + } + if (has_next_file_number_) { + PutVarint32(dst, kNextFileNumber); + PutVarint64(dst, next_file_number_); + } + if (has_last_sequence_) { + PutVarint32(dst, kLastSequence); + PutVarint64(dst, last_sequence_); + } + + for (size_t i = 0; i < compact_pointers_.size(); i++) { + PutVarint32(dst, kCompactPointer); + PutVarint32(dst, compact_pointers_[i].first); // level + PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); + } + + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + PutVarint32(dst, kDeletedFile); + PutVarint32(dst, iter->first); // level + PutVarint64(dst, iter->second); // file number + } + + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + PutVarint32(dst, kNewFile); + PutVarint32(dst, new_files_[i].first); // level + PutVarint64(dst, f.number); + PutVarint64(dst, f.file_size); + PutLengthPrefixedSlice(dst, f.smallest.Encode()); + PutLengthPrefixedSlice(dst, f.largest.Encode()); + } +} + +static bool GetInternalKey(Slice* input, InternalKey* dst) { + Slice str; + if (GetLengthPrefixedSlice(input, &str)) { + dst->DecodeFrom(str); + return true; + } else { + return false; + } +} + +static bool GetLevel(Slice* input, int* level) { + uint32_t v; + if (GetVarint32(input, &v) && + v < config::kNumLevels) { + *level = v; + return true; + } else { + return false; + } +} + +Status VersionEdit::DecodeFrom(const Slice& src) { + Clear(); + Slice input = src; + const char* msg = NULL; + uint32_t tag; + + // Temporary storage for parsing + int level; + uint64_t number; + FileMetaData f; + Slice str; + InternalKey key; + + while (msg == NULL && GetVarint32(&input, &tag)) { + switch (tag) { + case kComparator: + if (GetLengthPrefixedSlice(&input, &str)) { + comparator_ = str.ToString(); + has_comparator_ = true; + } else { + msg = "comparator name"; + } + break; + + case kLogNumber: + if (GetVarint64(&input, &log_number_)) { + has_log_number_ = true; + } else { + msg = "log number"; + } + break; + + case kPrevLogNumber: + if (GetVarint64(&input, &prev_log_number_)) { + has_prev_log_number_ = true; + } else { + msg = "previous log number"; + } + break; + + case kNextFileNumber: + if (GetVarint64(&input, &next_file_number_)) { + has_next_file_number_ = true; + } else { + msg = "next file number"; + } + break; + + case kLastSequence: + if (GetVarint64(&input, &last_sequence_)) { + has_last_sequence_ = true; + } else { + msg = "last sequence number"; + } + break; + + case kCompactPointer: + if (GetLevel(&input, &level) && + GetInternalKey(&input, &key)) { + compact_pointers_.push_back(std::make_pair(level, key)); + } else { + msg = "compaction pointer"; + } + break; + + case kDeletedFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &number)) { + deleted_files_.insert(std::make_pair(level, number)); + } else { + msg = "deleted file"; + } + break; + + case kNewFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &f.number) && + GetVarint64(&input, &f.file_size) && + GetInternalKey(&input, &f.smallest) && + GetInternalKey(&input, &f.largest)) { + new_files_.push_back(std::make_pair(level, f)); + } else { + msg = "new-file entry"; + } + break; + + default: + msg = "unknown tag"; + break; + } + } + + if (msg == NULL && !input.empty()) { + msg = "invalid tag"; + } + + Status result; + if (msg != NULL) { + result = Status::Corruption("VersionEdit", msg); + } + return result; +} + +std::string VersionEdit::DebugString() const { + std::string r; + r.append("VersionEdit {"); + if (has_comparator_) { + r.append("\n Comparator: "); + r.append(comparator_); + } + if (has_log_number_) { + r.append("\n LogNumber: "); + AppendNumberTo(&r, log_number_); + } + if (has_prev_log_number_) { + r.append("\n PrevLogNumber: "); + AppendNumberTo(&r, prev_log_number_); + } + if (has_next_file_number_) { + r.append("\n NextFile: "); + AppendNumberTo(&r, next_file_number_); + } + if (has_last_sequence_) { + r.append("\n LastSeq: "); + AppendNumberTo(&r, last_sequence_); + } + for (size_t i = 0; i < compact_pointers_.size(); i++) { + r.append("\n CompactPointer: "); + AppendNumberTo(&r, compact_pointers_[i].first); + r.append(" "); + r.append(compact_pointers_[i].second.DebugString()); + } + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + r.append("\n DeleteFile: "); + AppendNumberTo(&r, iter->first); + r.append(" "); + AppendNumberTo(&r, iter->second); + } + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + r.append("\n AddFile: "); + AppendNumberTo(&r, new_files_[i].first); + r.append(" "); + AppendNumberTo(&r, f.number); + r.append(" "); + AppendNumberTo(&r, f.file_size); + r.append(" "); + r.append(f.smallest.DebugString()); + r.append(" .. "); + r.append(f.largest.DebugString()); + } + r.append("\n}\n"); + return r; +} + +} // namespace leveldb diff --git a/db/version_edit.h b/db/version_edit.h new file mode 100644 index 000000000..eaef77b32 --- /dev/null +++ b/db/version_edit.h @@ -0,0 +1,107 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_ +#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ + +#include +#include +#include +#include "db/dbformat.h" + +namespace leveldb { + +class VersionSet; + +struct FileMetaData { + int refs; + int allowed_seeks; // Seeks allowed until compaction + uint64_t number; + uint64_t file_size; // File size in bytes + InternalKey smallest; // Smallest internal key served by table + InternalKey largest; // Largest internal key served by table + + FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { } +}; + +class VersionEdit { + public: + VersionEdit() { Clear(); } + ~VersionEdit() { } + + void Clear(); + + void SetComparatorName(const Slice& name) { + has_comparator_ = true; + comparator_ = name.ToString(); + } + void SetLogNumber(uint64_t num) { + has_log_number_ = true; + log_number_ = num; + } + void SetPrevLogNumber(uint64_t num) { + has_prev_log_number_ = true; + prev_log_number_ = num; + } + void SetNextFile(uint64_t num) { + has_next_file_number_ = true; + next_file_number_ = num; + } + void SetLastSequence(SequenceNumber seq) { + has_last_sequence_ = true; + last_sequence_ = seq; + } + void SetCompactPointer(int level, const InternalKey& key) { + compact_pointers_.push_back(std::make_pair(level, key)); + } + + // Add the specified file at the specified number. + // REQUIRES: This version has not been saved (see VersionSet::SaveTo) + // REQUIRES: "smallest" and "largest" are smallest and largest keys in file + void AddFile(int level, uint64_t file, + uint64_t file_size, + const InternalKey& smallest, + const InternalKey& largest) { + FileMetaData f; + f.number = file; + f.file_size = file_size; + f.smallest = smallest; + f.largest = largest; + new_files_.push_back(std::make_pair(level, f)); + } + + // Delete the specified "file" from the specified "level". + void DeleteFile(int level, uint64_t file) { + deleted_files_.insert(std::make_pair(level, file)); + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(const Slice& src); + + std::string DebugString() const; + + private: + friend class VersionSet; + + typedef std::set< std::pair > DeletedFileSet; + + std::string comparator_; + uint64_t log_number_; + uint64_t prev_log_number_; + uint64_t next_file_number_; + SequenceNumber last_sequence_; + bool has_comparator_; + bool has_log_number_; + bool has_prev_log_number_; + bool has_next_file_number_; + bool has_last_sequence_; + + std::vector< std::pair > compact_pointers_; + DeletedFileSet deleted_files_; + std::vector< std::pair > new_files_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/db/version_edit_test.cc b/db/version_edit_test.cc new file mode 100644 index 000000000..280310b49 --- /dev/null +++ b/db/version_edit_test.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" +#include "util/testharness.h" + +namespace leveldb { + +static void TestEncodeDecode(const VersionEdit& edit) { + std::string encoded, encoded2; + edit.EncodeTo(&encoded); + VersionEdit parsed; + Status s = parsed.DecodeFrom(encoded); + ASSERT_TRUE(s.ok()) << s.ToString(); + parsed.EncodeTo(&encoded2); + ASSERT_EQ(encoded, encoded2); +} + +class VersionEditTest { }; + +TEST(VersionEditTest, EncodeDecode) { + static const uint64_t kBig = 1ull << 50; + + VersionEdit edit; + for (int i = 0; i < 4; i++) { + TestEncodeDecode(edit); + edit.AddFile(3, kBig + 300 + i, kBig + 400 + i, + InternalKey("foo", kBig + 500 + i, kTypeValue), + InternalKey("zoo", kBig + 600 + i, kTypeDeletion)); + edit.DeleteFile(4, kBig + 700 + i); + edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue)); + } + + edit.SetComparatorName("foo"); + edit.SetLogNumber(kBig + 100); + edit.SetNextFile(kBig + 200); + edit.SetLastSequence(kBig + 1000); + TestEncodeDecode(edit); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/version_set.cc b/db/version_set.cc new file mode 100644 index 000000000..7d0a5de2b --- /dev/null +++ b/db/version_set.cc @@ -0,0 +1,1438 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" + +#include +#include +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "leveldb/env.h" +#include "leveldb/table_builder.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +static const int kTargetFileSize = 2 * 1048576; + +// Maximum bytes of overlaps in grandparent (i.e., level+2) before we +// stop building a single file in a level->level+1 compaction. +static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; + +// Maximum number of bytes in all compacted files. We avoid expanding +// the lower level file set of a compaction if it would make the +// total compaction cover more than this many bytes. +static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; + +static double MaxBytesForLevel(int level) { + // Note: the result for level zero is not really used since we set + // the level-0 compaction threshold based on number of files. + double result = 10 * 1048576.0; // Result for both level-0 and level-1 + while (level > 1) { + result *= 10; + level--; + } + return result; +} + +static uint64_t MaxFileSizeForLevel(int level) { + return kTargetFileSize; // We could vary per level to reduce number of files? +} + +static int64_t TotalFileSize(const std::vector& files) { + int64_t sum = 0; + for (size_t i = 0; i < files.size(); i++) { + sum += files[i]->file_size; + } + return sum; +} + +namespace { +std::string IntSetToString(const std::set& s) { + std::string result = "{"; + for (std::set::const_iterator it = s.begin(); + it != s.end(); + ++it) { + result += (result.size() > 1) ? "," : ""; + result += NumberToString(*it); + } + result += "}"; + return result; +} +} // namespace + +Version::~Version() { + assert(refs_ == 0); + + // Remove from linked list + prev_->next_ = next_; + next_->prev_ = prev_; + + // Drop references to files + for (int level = 0; level < config::kNumLevels; level++) { + for (size_t i = 0; i < files_[level].size(); i++) { + FileMetaData* f = files_[level][i]; + assert(f->refs > 0); + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } +} + +int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key) { + uint32_t left = 0; + uint32_t right = files.size(); + while (left < right) { + uint32_t mid = (left + right) / 2; + const FileMetaData* f = files[mid]; + if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { + // Key at "mid.largest" is < "target". Therefore all + // files at or before "mid" are uninteresting. + left = mid + 1; + } else { + // Key at "mid.largest" is >= "target". Therefore all files + // after "mid" are uninteresting. + right = mid; + } + } + return right; +} + +static bool AfterFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs before all keys and is therefore never after *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->largest.user_key()) > 0); +} + +static bool BeforeFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs after all keys and is therefore never before *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->smallest.user_key()) < 0); +} + +bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + const Comparator* ucmp = icmp.user_comparator(); + if (!disjoint_sorted_files) { + // Need to check against all files + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + if (AfterFile(ucmp, smallest_user_key, f) || + BeforeFile(ucmp, largest_user_key, f)) { + // No overlap + } else { + return true; // Overlap + } + } + return false; + } + + // Binary search over file list + uint32_t index = 0; + if (smallest_user_key != NULL) { + // Find the earliest possible internal key for smallest_user_key + InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); + index = FindFile(icmp, files, small.Encode()); + } + + if (index >= files.size()) { + // beginning of range is after all files, so no overlap. + return false; + } + + return !BeforeFile(ucmp, largest_user_key, files[index]); +} + +// An internal iterator. For a given version/level pair, yields +// information about the files in the level. For a given entry, key() +// is the largest key that occurs in the file, and value() is an +// 16-byte value containing the file number and file size, both +// encoded using EncodeFixed64. +class Version::LevelFileNumIterator : public Iterator { + public: + LevelFileNumIterator(const InternalKeyComparator& icmp, + const std::vector* flist) + : icmp_(icmp), + flist_(flist), + index_(flist->size()) { // Marks as invalid + } + virtual bool Valid() const { + return index_ < flist_->size(); + } + virtual void Seek(const Slice& target) { + index_ = FindFile(icmp_, *flist_, target); + } + virtual void SeekToFirst() { index_ = 0; } + virtual void SeekToLast() { + index_ = flist_->empty() ? 0 : flist_->size() - 1; + } + virtual void Next() { + assert(Valid()); + index_++; + } + virtual void Prev() { + assert(Valid()); + if (index_ == 0) { + index_ = flist_->size(); // Marks as invalid + } else { + index_--; + } + } + Slice key() const { + assert(Valid()); + return (*flist_)[index_]->largest.Encode(); + } + Slice value() const { + assert(Valid()); + EncodeFixed64(value_buf_, (*flist_)[index_]->number); + EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size); + return Slice(value_buf_, sizeof(value_buf_)); + } + virtual Status status() const { return Status::OK(); } + private: + const InternalKeyComparator icmp_; + const std::vector* const flist_; + uint32_t index_; + + // Backing store for value(). Holds the file number and size. + mutable char value_buf_[16]; +}; + +static Iterator* GetFileIterator(void* arg, + const ReadOptions& options, + const Slice& file_value) { + TableCache* cache = reinterpret_cast(arg); + if (file_value.size() != 16) { + return NewErrorIterator( + Status::Corruption("FileReader invoked with unexpected value")); + } else { + return cache->NewIterator(options, + DecodeFixed64(file_value.data()), + DecodeFixed64(file_value.data() + 8)); + } +} + +Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, + int level) const { + return NewTwoLevelIterator( + new LevelFileNumIterator(vset_->icmp_, &files_[level]), + &GetFileIterator, vset_->table_cache_, options); +} + +void Version::AddIterators(const ReadOptions& options, + std::vector* iters) { + // Merge all level zero files together since they may overlap + for (size_t i = 0; i < files_[0].size(); i++) { + iters->push_back( + vset_->table_cache_->NewIterator( + options, files_[0][i]->number, files_[0][i]->file_size)); + } + + // For levels > 0, we can use a concatenating iterator that sequentially + // walks through the non-overlapping files in the level, opening them + // lazily. + for (int level = 1; level < config::kNumLevels; level++) { + if (!files_[level].empty()) { + iters->push_back(NewConcatenatingIterator(options, level)); + } + } +} + +// Callback from TableCache::Get() +namespace { +enum SaverState { + kNotFound, + kFound, + kDeleted, + kCorrupt, +}; +struct Saver { + SaverState state; + const Comparator* ucmp; + Slice user_key; + std::string* value; +}; +} +static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { + Saver* s = reinterpret_cast(arg); + ParsedInternalKey parsed_key; + if (!ParseInternalKey(ikey, &parsed_key)) { + s->state = kCorrupt; + } else { + if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { + s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; + if (s->state == kFound) { + s->value->assign(v.data(), v.size()); + } + } + } +} + +static bool NewestFirst(FileMetaData* a, FileMetaData* b) { + return a->number > b->number; +} + +Status Version::Get(const ReadOptions& options, + const LookupKey& k, + std::string* value, + GetStats* stats) { + Slice ikey = k.internal_key(); + Slice user_key = k.user_key(); + const Comparator* ucmp = vset_->icmp_.user_comparator(); + Status s; + + stats->seek_file = NULL; + stats->seek_file_level = -1; + FileMetaData* last_file_read = NULL; + int last_file_read_level = -1; + + // We can search level-by-level since entries never hop across + // levels. Therefore we are guaranteed that if we find data + // in an smaller level, later levels are irrelevant. + std::vector tmp; + FileMetaData* tmp2; + for (int level = 0; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Get the list of files to search in this level + FileMetaData* const* files = &files_[level][0]; + if (level == 0) { + // Level-0 files may overlap each other. Find all files that + // overlap user_key and process them in order from newest to oldest. + tmp.reserve(num_files); + for (uint32_t i = 0; i < num_files; i++) { + FileMetaData* f = files[i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (tmp.empty()) continue; + + std::sort(tmp.begin(), tmp.end(), NewestFirst); + files = &tmp[0]; + num_files = tmp.size(); + } else { + // Binary search to find earliest index whose largest key >= ikey. + uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); + if (index >= num_files) { + files = NULL; + num_files = 0; + } else { + tmp2 = files[index]; + if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { + // All of "tmp2" is past any data for user_key + files = NULL; + num_files = 0; + } else { + files = &tmp2; + num_files = 1; + } + } + } + + for (uint32_t i = 0; i < num_files; ++i) { + if (last_file_read != NULL && stats->seek_file == NULL) { + // We have had more than one seek for this read. Charge the 1st file. + stats->seek_file = last_file_read; + stats->seek_file_level = last_file_read_level; + } + + FileMetaData* f = files[i]; + last_file_read = f; + last_file_read_level = level; + + Saver saver; + saver.state = kNotFound; + saver.ucmp = ucmp; + saver.user_key = user_key; + saver.value = value; + s = vset_->table_cache_->Get(options, f->number, f->file_size, + ikey, &saver, SaveValue); + if (!s.ok()) { + return s; + } + switch (saver.state) { + case kNotFound: + break; // Keep searching in other files + case kFound: + return s; + case kDeleted: + s = Status::NotFound(Slice()); // Use empty error message for speed + return s; + case kCorrupt: + s = Status::Corruption("corrupted key for ", user_key); + return s; + } + } + } + + return Status::NotFound(Slice()); // Use an empty error message for speed +} + +bool Version::UpdateStats(const GetStats& stats) { + FileMetaData* f = stats.seek_file; + if (f != NULL) { + f->allowed_seeks--; + if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) { + file_to_compact_ = f; + file_to_compact_level_ = stats.seek_file_level; + return true; + } + } + return false; +} + +void Version::Ref() { + ++refs_; +} + +void Version::Unref() { + assert(this != &vset_->dummy_versions_); + assert(refs_ >= 1); + --refs_; + if (refs_ == 0) { + delete this; + } +} + +bool Version::OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], + smallest_user_key, largest_user_key); +} + +int Version::PickLevelForMemTableOutput( + const Slice& smallest_user_key, + const Slice& largest_user_key) { + int level = 0; + if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { + // Push to next level if there is no overlap in next level, + // and the #bytes overlapping in the level after that are limited. + InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey limit(largest_user_key, 0, static_cast(0)); + std::vector overlaps; + while (level < config::kMaxMemCompactLevel) { + if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { + break; + } + GetOverlappingInputs(level + 2, &start, &limit, &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > kMaxGrandParentOverlapBytes) { + break; + } + level++; + } + } + return level; +} + +// Store in "*inputs" all files in "level" that overlap [begin,end] +void Version::GetOverlappingInputs( + int level, + const InternalKey* begin, + const InternalKey* end, + std::vector* inputs) { + inputs->clear(); + Slice user_begin, user_end; + if (begin != NULL) { + user_begin = begin->user_key(); + } + if (end != NULL) { + user_end = end->user_key(); + } + const Comparator* user_cmp = vset_->icmp_.user_comparator(); + for (size_t i = 0; i < files_[level].size(); ) { + FileMetaData* f = files_[level][i++]; + const Slice file_start = f->smallest.user_key(); + const Slice file_limit = f->largest.user_key(); + if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) { + // "f" is completely before specified range; skip it + } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) { + // "f" is completely after specified range; skip it + } else { + inputs->push_back(f); + if (level == 0) { + // Level-0 files may overlap each other. So check if the newly + // added file has expanded the range. If so, restart search. + if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) { + user_begin = file_start; + inputs->clear(); + i = 0; + } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) { + user_end = file_limit; + inputs->clear(); + i = 0; + } + } + } + } +} + +std::string Version::DebugString() const { + std::string r; + for (int level = 0; level < config::kNumLevels; level++) { + // E.g., + // --- level 1 --- + // 17:123['a' .. 'd'] + // 20:43['e' .. 'g'] + r.append("--- level "); + AppendNumberTo(&r, level); + r.append(" ---\n"); + const std::vector& files = files_[level]; + for (size_t i = 0; i < files.size(); i++) { + r.push_back(' '); + AppendNumberTo(&r, files[i]->number); + r.push_back(':'); + AppendNumberTo(&r, files[i]->file_size); + r.append("["); + r.append(files[i]->smallest.DebugString()); + r.append(" .. "); + r.append(files[i]->largest.DebugString()); + r.append("]\n"); + } + } + return r; +} + +// A helper class so we can efficiently apply a whole sequence +// of edits to a particular state without creating intermediate +// Versions that contain full copies of the intermediate state. +class VersionSet::Builder { + private: + // Helper to sort by v->files_[file_number].smallest + struct BySmallestKey { + const InternalKeyComparator* internal_comparator; + + bool operator()(FileMetaData* f1, FileMetaData* f2) const { + int r = internal_comparator->Compare(f1->smallest, f2->smallest); + if (r != 0) { + return (r < 0); + } else { + // Break ties by file number + return (f1->number < f2->number); + } + } + }; + + typedef std::set FileSet; + struct LevelState { + std::set deleted_files; + FileSet* added_files; + }; + + VersionSet* vset_; + Version* base_; + LevelState levels_[config::kNumLevels]; + + public: + // Initialize a builder with the files from *base and other info from *vset + Builder(VersionSet* vset, Version* base) + : vset_(vset), + base_(base) { + base_->Ref(); + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + levels_[level].added_files = new FileSet(cmp); + } + } + + ~Builder() { + for (int level = 0; level < config::kNumLevels; level++) { + const FileSet* added = levels_[level].added_files; + std::vector to_unref; + to_unref.reserve(added->size()); + for (FileSet::const_iterator it = added->begin(); + it != added->end(); ++it) { + to_unref.push_back(*it); + } + delete added; + for (uint32_t i = 0; i < to_unref.size(); i++) { + FileMetaData* f = to_unref[i]; + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } + base_->Unref(); + } + + // Apply all of the edits in *edit to the current state. + void Apply(VersionEdit* edit) { + // Update compaction pointers + for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { + const int level = edit->compact_pointers_[i].first; + vset_->compact_pointer_[level] = + edit->compact_pointers_[i].second.Encode().ToString(); + } + + // Delete files + const VersionEdit::DeletedFileSet& del = edit->deleted_files_; + for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); + iter != del.end(); + ++iter) { + const int level = iter->first; + const uint64_t number = iter->second; + levels_[level].deleted_files.insert(number); + } + + // Add new files + for (size_t i = 0; i < edit->new_files_.size(); i++) { + const int level = edit->new_files_[i].first; + FileMetaData* f = new FileMetaData(edit->new_files_[i].second); + f->refs = 1; + + // We arrange to automatically compact this file after + // a certain number of seeks. Let's assume: + // (1) One seek costs 10ms + // (2) Writing or reading 1MB costs 10ms (100MB/s) + // (3) A compaction of 1MB does 25MB of IO: + // 1MB read from this level + // 10-12MB read from next level (boundaries may be misaligned) + // 10-12MB written to next level + // This implies that 25 seeks cost the same as the compaction + // of 1MB of data. I.e., one seek costs approximately the + // same as the compaction of 40KB of data. We are a little + // conservative and allow approximately one seek for every 16KB + // of data before triggering a compaction. + f->allowed_seeks = (f->file_size / 16384); + if (f->allowed_seeks < 100) f->allowed_seeks = 100; + + levels_[level].deleted_files.erase(f->number); + levels_[level].added_files->insert(f); + } + } + + // Save the current state in *v. + void SaveTo(Version* v) { + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + // Merge the set of added files with the set of pre-existing files. + // Drop any deleted files. Store the result in *v. + const std::vector& base_files = base_->files_[level]; + std::vector::const_iterator base_iter = base_files.begin(); + std::vector::const_iterator base_end = base_files.end(); + const FileSet* added = levels_[level].added_files; + v->files_[level].reserve(base_files.size() + added->size()); + for (FileSet::const_iterator added_iter = added->begin(); + added_iter != added->end(); + ++added_iter) { + // Add all smaller files listed in base_ + for (std::vector::const_iterator bpos + = std::upper_bound(base_iter, base_end, *added_iter, cmp); + base_iter != bpos; + ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + + MaybeAddFile(v, level, *added_iter); + } + + // Add remaining base files + for (; base_iter != base_end; ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + +#ifndef NDEBUG + // Make sure there is no overlap in levels > 0 + if (level > 0) { + for (uint32_t i = 1; i < v->files_[level].size(); i++) { + const InternalKey& prev_end = v->files_[level][i-1]->largest; + const InternalKey& this_begin = v->files_[level][i]->smallest; + if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { + fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", + prev_end.DebugString().c_str(), + this_begin.DebugString().c_str()); + abort(); + } + } + } +#endif + } + } + + void MaybeAddFile(Version* v, int level, FileMetaData* f) { + if (levels_[level].deleted_files.count(f->number) > 0) { + // File is deleted: do nothing + } else { + std::vector* files = &v->files_[level]; + if (level > 0 && !files->empty()) { + // Must not overlap + assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest, + f->smallest) < 0); + } + f->refs++; + files->push_back(f); + } + } +}; + +VersionSet::VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator* cmp) + : env_(options->env), + dbname_(dbname), + options_(options), + table_cache_(table_cache), + icmp_(*cmp), + next_file_number_(2), + manifest_file_number_(0), // Filled by Recover() + last_sequence_(0), + log_number_(0), + prev_log_number_(0), + descriptor_file_(NULL), + descriptor_log_(NULL), + dummy_versions_(this), + current_(NULL) { + AppendVersion(new Version(this)); +} + +VersionSet::~VersionSet() { + current_->Unref(); + assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty + delete descriptor_log_; + delete descriptor_file_; +} + +void VersionSet::AppendVersion(Version* v) { + // Make "v" current + assert(v->refs_ == 0); + assert(v != current_); + if (current_ != NULL) { + current_->Unref(); + } + current_ = v; + v->Ref(); + + // Append to linked list + v->prev_ = dummy_versions_.prev_; + v->next_ = &dummy_versions_; + v->prev_->next_ = v; + v->next_->prev_ = v; +} + +Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { + if (edit->has_log_number_) { + assert(edit->log_number_ >= log_number_); + assert(edit->log_number_ < next_file_number_); + } else { + edit->SetLogNumber(log_number_); + } + + if (!edit->has_prev_log_number_) { + edit->SetPrevLogNumber(prev_log_number_); + } + + edit->SetNextFile(next_file_number_); + edit->SetLastSequence(last_sequence_); + + Version* v = new Version(this); + { + Builder builder(this, current_); + builder.Apply(edit); + builder.SaveTo(v); + } + Finalize(v); + + // Initialize new descriptor log file if necessary by creating + // a temporary file that contains a snapshot of the current version. + std::string new_manifest_file; + Status s; + if (descriptor_log_ == NULL) { + // No reason to unlock *mu here since we only hit this path in the + // first call to LogAndApply (when opening the database). + assert(descriptor_file_ == NULL); + new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); + edit->SetNextFile(next_file_number_); + s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); + if (s.ok()) { + descriptor_log_ = new log::Writer(descriptor_file_); + s = WriteSnapshot(descriptor_log_); + } + } + + // Unlock during expensive MANIFEST log write + { + mu->Unlock(); + + // Write new record to MANIFEST log + if (s.ok()) { + std::string record; + edit->EncodeTo(&record); + s = descriptor_log_->AddRecord(record); + if (s.ok()) { + s = descriptor_file_->Sync(); + } + if (!s.ok()) { + Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); + if (ManifestContains(record)) { + Log(options_->info_log, + "MANIFEST contains log record despite error; advancing to new " + "version to prevent mismatch between in-memory and logged state"); + s = Status::OK(); + } + } + } + + // If we just created a new descriptor file, install it by writing a + // new CURRENT file that points to it. + if (s.ok() && !new_manifest_file.empty()) { + s = SetCurrentFile(env_, dbname_, manifest_file_number_); + // No need to double-check MANIFEST in case of error since it + // will be discarded below. + } + + mu->Lock(); + } + + // Install the new version + if (s.ok()) { + AppendVersion(v); + log_number_ = edit->log_number_; + prev_log_number_ = edit->prev_log_number_; + } else { + delete v; + if (!new_manifest_file.empty()) { + delete descriptor_log_; + delete descriptor_file_; + descriptor_log_ = NULL; + descriptor_file_ = NULL; + env_->DeleteFile(new_manifest_file); + } + } + + return s; +} + +Status VersionSet::Recover() { + struct LogReporter : public log::Reader::Reporter { + Status* status; + virtual void Corruption(size_t bytes, const Status& s) { + if (this->status->ok()) *this->status = s; + } + }; + + // Read "CURRENT" file, which contains a pointer to the current manifest file + std::string current; + Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); + if (!s.ok()) { + return s; + } + if (current.empty() || current[current.size()-1] != '\n') { + return Status::Corruption("CURRENT file does not end with newline"); + } + current.resize(current.size() - 1); + + std::string dscname = dbname_ + "/" + current; + SequentialFile* file; + s = env_->NewSequentialFile(dscname, &file); + if (!s.ok()) { + return s; + } + + bool have_log_number = false; + bool have_prev_log_number = false; + bool have_next_file = false; + bool have_last_sequence = false; + uint64_t next_file = 0; + uint64_t last_sequence = 0; + uint64_t log_number = 0; + uint64_t prev_log_number = 0; + Builder builder(this, current_); + + { + LogReporter reporter; + reporter.status = &s; + log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch) && s.ok()) { + VersionEdit edit; + s = edit.DecodeFrom(record); + if (s.ok()) { + if (edit.has_comparator_ && + edit.comparator_ != icmp_.user_comparator()->Name()) { + s = Status::InvalidArgument( + edit.comparator_ + " does not match existing comparator ", + icmp_.user_comparator()->Name()); + } + } + + if (s.ok()) { + builder.Apply(&edit); + } + + if (edit.has_log_number_) { + log_number = edit.log_number_; + have_log_number = true; + } + + if (edit.has_prev_log_number_) { + prev_log_number = edit.prev_log_number_; + have_prev_log_number = true; + } + + if (edit.has_next_file_number_) { + next_file = edit.next_file_number_; + have_next_file = true; + } + + if (edit.has_last_sequence_) { + last_sequence = edit.last_sequence_; + have_last_sequence = true; + } + } + } + delete file; + file = NULL; + + if (s.ok()) { + if (!have_next_file) { + s = Status::Corruption("no meta-nextfile entry in descriptor"); + } else if (!have_log_number) { + s = Status::Corruption("no meta-lognumber entry in descriptor"); + } else if (!have_last_sequence) { + s = Status::Corruption("no last-sequence-number entry in descriptor"); + } + + if (!have_prev_log_number) { + prev_log_number = 0; + } + + MarkFileNumberUsed(prev_log_number); + MarkFileNumberUsed(log_number); + } + + if (s.ok()) { + Version* v = new Version(this); + builder.SaveTo(v); + // Install recovered version + Finalize(v); + AppendVersion(v); + manifest_file_number_ = next_file; + next_file_number_ = next_file + 1; + last_sequence_ = last_sequence; + log_number_ = log_number; + prev_log_number_ = prev_log_number; + } + + return s; +} + +void VersionSet::MarkFileNumberUsed(uint64_t number) { + if (next_file_number_ <= number) { + next_file_number_ = number + 1; + } +} + +void VersionSet::Finalize(Version* v) { + // Precomputed best level for next compaction + int best_level = -1; + double best_score = -1; + + for (int level = 0; level < config::kNumLevels-1; level++) { + double score; + if (level == 0) { + // We treat level-0 specially by bounding the number of files + // instead of number of bytes for two reasons: + // + // (1) With larger write-buffer sizes, it is nice not to do too + // many level-0 compactions. + // + // (2) The files in level-0 are merged on every read and + // therefore we wish to avoid too many files when the individual + // file size is small (perhaps because of a small write-buffer + // setting, or very high compression ratios, or lots of + // overwrites/deletions). + score = v->files_[level].size() / + static_cast(config::kL0_CompactionTrigger); + } else { + // Compute the ratio of current size to size limit. + const uint64_t level_bytes = TotalFileSize(v->files_[level]); + score = static_cast(level_bytes) / MaxBytesForLevel(level); + } + + if (score > best_score) { + best_level = level; + best_score = score; + } + } + + v->compaction_level_ = best_level; + v->compaction_score_ = best_score; +} + +Status VersionSet::WriteSnapshot(log::Writer* log) { + // TODO: Break up into multiple records to reduce memory usage on recovery? + + // Save metadata + VersionEdit edit; + edit.SetComparatorName(icmp_.user_comparator()->Name()); + + // Save compaction pointers + for (int level = 0; level < config::kNumLevels; level++) { + if (!compact_pointer_[level].empty()) { + InternalKey key; + key.DecodeFrom(compact_pointer_[level]); + edit.SetCompactPointer(level, key); + } + } + + // Save files + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = current_->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); + } + } + + std::string record; + edit.EncodeTo(&record); + return log->AddRecord(record); +} + +int VersionSet::NumLevelFiles(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return current_->files_[level].size(); +} + +const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { + // Update code if kNumLevels changes + assert(config::kNumLevels == 7); + snprintf(scratch->buffer, sizeof(scratch->buffer), + "files[ %d %d %d %d %d %d %d ]", + int(current_->files_[0].size()), + int(current_->files_[1].size()), + int(current_->files_[2].size()), + int(current_->files_[3].size()), + int(current_->files_[4].size()), + int(current_->files_[5].size()), + int(current_->files_[6].size())); + return scratch->buffer; +} + +// Return true iff the manifest contains the specified record. +bool VersionSet::ManifestContains(const std::string& record) const { + std::string fname = DescriptorFileName(dbname_, manifest_file_number_); + Log(options_->info_log, "ManifestContains: checking %s\n", fname.c_str()); + SequentialFile* file = NULL; + Status s = env_->NewSequentialFile(fname, &file); + if (!s.ok()) { + Log(options_->info_log, "ManifestContains: %s\n", s.ToString().c_str()); + return false; + } + log::Reader reader(file, NULL, true/*checksum*/, 0); + Slice r; + std::string scratch; + bool result = false; + while (reader.ReadRecord(&r, &scratch)) { + if (r == Slice(record)) { + result = true; + break; + } + } + delete file; + Log(options_->info_log, "ManifestContains: result = %d\n", result ? 1 : 0); + return result; +} + +uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { + uint64_t result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + if (icmp_.Compare(files[i]->largest, ikey) <= 0) { + // Entire file is before "ikey", so just add the file size + result += files[i]->file_size; + } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { + // Entire file is after "ikey", so ignore + if (level > 0) { + // Files other than level 0 are sorted by meta->smallest, so + // no further files in this level will contain data for + // "ikey". + break; + } + } else { + // "ikey" falls in the range for this table. Add the + // approximate offset of "ikey" within the table. + Table* tableptr; + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); + if (tableptr != NULL) { + result += tableptr->ApproximateOffsetOf(ikey.Encode()); + } + delete iter; + } + } + } + return result; +} + +void VersionSet::AddLiveFiles(std::set* live) { + for (Version* v = dummy_versions_.next_; + v != &dummy_versions_; + v = v->next_) { + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + live->insert(files[i]->number); + } + } + } +} + +int64_t VersionSet::NumLevelBytes(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return TotalFileSize(current_->files_[level]); +} + +int64_t VersionSet::MaxNextLevelOverlappingBytes() { + int64_t result = 0; + std::vector overlaps; + for (int level = 1; level < config::kNumLevels - 1; level++) { + for (size_t i = 0; i < current_->files_[level].size(); i++) { + const FileMetaData* f = current_->files_[level][i]; + current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest, + &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > result) { + result = sum; + } + } + } + return result; +} + +// Stores the minimal range that covers all entries in inputs in +// *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest) { + assert(!inputs.empty()); + smallest->Clear(); + largest->Clear(); + for (size_t i = 0; i < inputs.size(); i++) { + FileMetaData* f = inputs[i]; + if (i == 0) { + *smallest = f->smallest; + *largest = f->largest; + } else { + if (icmp_.Compare(f->smallest, *smallest) < 0) { + *smallest = f->smallest; + } + if (icmp_.Compare(f->largest, *largest) > 0) { + *largest = f->largest; + } + } + } +} + +// Stores the minimal range that covers all entries in inputs1 and inputs2 +// in *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest) { + std::vector all = inputs1; + all.insert(all.end(), inputs2.begin(), inputs2.end()); + GetRange(all, smallest, largest); +} + +Iterator* VersionSet::MakeInputIterator(Compaction* c) { + ReadOptions options; + options.verify_checksums = options_->paranoid_checks; + options.fill_cache = false; + + // Level-0 files have to be merged together. For other levels, + // we will make a concatenating iterator per level. + // TODO(opt): use concatenating iterator for level-0 if there is no overlap + const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); + Iterator** list = new Iterator*[space]; + int num = 0; + for (int which = 0; which < 2; which++) { + if (!c->inputs_[which].empty()) { + if (c->level() + which == 0) { + const std::vector& files = c->inputs_[which]; + for (size_t i = 0; i < files.size(); i++) { + list[num++] = table_cache_->NewIterator( + options, files[i]->number, files[i]->file_size); + } + } else { + // Create concatenating iterator for the files from this level + list[num++] = NewTwoLevelIterator( + new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), + &GetFileIterator, table_cache_, options); + } + } + } + assert(num <= space); + Iterator* result = NewMergingIterator(&icmp_, list, num); + delete[] list; + return result; +} + +Compaction* VersionSet::PickCompaction() { + Compaction* c; + int level; + + // We prefer compactions triggered by too much data in a level over + // the compactions triggered by seeks. + const bool size_compaction = (current_->compaction_score_ >= 1); + const bool seek_compaction = (current_->file_to_compact_ != NULL); + if (size_compaction) { + level = current_->compaction_level_; + assert(level >= 0); + assert(level+1 < config::kNumLevels); + c = new Compaction(level); + + // Pick the first file that comes after compact_pointer_[level] + for (size_t i = 0; i < current_->files_[level].size(); i++) { + FileMetaData* f = current_->files_[level][i]; + if (compact_pointer_[level].empty() || + icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { + c->inputs_[0].push_back(f); + break; + } + } + if (c->inputs_[0].empty()) { + // Wrap-around to the beginning of the key space + c->inputs_[0].push_back(current_->files_[level][0]); + } + } else if (seek_compaction) { + level = current_->file_to_compact_level_; + c = new Compaction(level); + c->inputs_[0].push_back(current_->file_to_compact_); + } else { + return NULL; + } + + c->input_version_ = current_; + c->input_version_->Ref(); + + // Files in level 0 may overlap each other, so pick up all overlapping ones + if (level == 0) { + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + // Note that the next call will discard the file we placed in + // c->inputs_[0] earlier and replace it with an overlapping set + // which will include the picked file. + current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); + assert(!c->inputs_[0].empty()); + } + + SetupOtherInputs(c); + + return c; +} + +void VersionSet::SetupOtherInputs(Compaction* c) { + const int level = c->level(); + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + + current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]); + + // Get entire range covered by compaction + InternalKey all_start, all_limit; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + + // See if we can grow the number of inputs in "level" without + // changing the number of "level+1" files we pick up. + if (!c->inputs_[1].empty()) { + std::vector expanded0; + current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); + const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); + const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); + const int64_t expanded0_size = TotalFileSize(expanded0); + if (expanded0.size() > c->inputs_[0].size() && + inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { + InternalKey new_start, new_limit; + GetRange(expanded0, &new_start, &new_limit); + std::vector expanded1; + current_->GetOverlappingInputs(level+1, &new_start, &new_limit, + &expanded1); + if (expanded1.size() == c->inputs_[1].size()) { + Log(options_->info_log, + "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", + level, + int(c->inputs_[0].size()), + int(c->inputs_[1].size()), + long(inputs0_size), long(inputs1_size), + int(expanded0.size()), + int(expanded1.size()), + long(expanded0_size), long(inputs1_size)); + smallest = new_start; + largest = new_limit; + c->inputs_[0] = expanded0; + c->inputs_[1] = expanded1; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + } + } + } + + // Compute the set of grandparent files that overlap this compaction + // (parent == level+1; grandparent == level+2) + if (level + 2 < config::kNumLevels) { + current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, + &c->grandparents_); + } + + if (false) { + Log(options_->info_log, "Compacting %d '%s' .. '%s'", + level, + smallest.DebugString().c_str(), + largest.DebugString().c_str()); + } + + // Update the place where we will do the next compaction for this level. + // We update this immediately instead of waiting for the VersionEdit + // to be applied so that if the compaction fails, we will try a different + // key range next time. + compact_pointer_[level] = largest.Encode().ToString(); + c->edit_.SetCompactPointer(level, largest); +} + +Compaction* VersionSet::CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end) { + std::vector inputs; + current_->GetOverlappingInputs(level, begin, end, &inputs); + if (inputs.empty()) { + return NULL; + } + + // Avoid compacting too much in one shot in case the range is large. + const uint64_t limit = MaxFileSizeForLevel(level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } + } + + Compaction* c = new Compaction(level); + c->input_version_ = current_; + c->input_version_->Ref(); + c->inputs_[0] = inputs; + SetupOtherInputs(c); + return c; +} + +Compaction::Compaction(int level) + : level_(level), + max_output_file_size_(MaxFileSizeForLevel(level)), + input_version_(NULL), + grandparent_index_(0), + seen_key_(false), + overlapped_bytes_(0) { + for (int i = 0; i < config::kNumLevels; i++) { + level_ptrs_[i] = 0; + } +} + +Compaction::~Compaction() { + if (input_version_ != NULL) { + input_version_->Unref(); + } +} + +bool Compaction::IsTrivialMove() const { + // Avoid a move if there is lots of overlapping grandparent data. + // Otherwise, the move could create a parent file that will require + // a very expensive merge later on. + return (num_input_files(0) == 1 && + num_input_files(1) == 0 && + TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); +} + +void Compaction::AddInputDeletions(VersionEdit* edit) { + for (int which = 0; which < 2; which++) { + for (size_t i = 0; i < inputs_[which].size(); i++) { + edit->DeleteFile(level_ + which, inputs_[which][i]->number); + } + } +} + +bool Compaction::IsBaseLevelForKey(const Slice& user_key) { + // Maybe use binary search to find right entry instead of linear search? + const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); + for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { + const std::vector& files = input_version_->files_[lvl]; + for (; level_ptrs_[lvl] < files.size(); ) { + FileMetaData* f = files[level_ptrs_[lvl]]; + if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { + // We've advanced far enough + if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { + // Key falls in this file's range, so definitely not base level + return false; + } + break; + } + level_ptrs_[lvl]++; + } + } + return true; +} + +bool Compaction::ShouldStopBefore(const Slice& internal_key) { + // Scan to find earliest grandparent file that contains key. + const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; + while (grandparent_index_ < grandparents_.size() && + icmp->Compare(internal_key, + grandparents_[grandparent_index_]->largest.Encode()) > 0) { + if (seen_key_) { + overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; + } + grandparent_index_++; + } + seen_key_ = true; + + if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { + // Too much overlap for current output; start new output + overlapped_bytes_ = 0; + return true; + } else { + return false; + } +} + +void Compaction::ReleaseInputs() { + if (input_version_ != NULL) { + input_version_->Unref(); + input_version_ = NULL; + } +} + +} // namespace leveldb diff --git a/db/version_set.h b/db/version_set.h new file mode 100644 index 000000000..9d084fdb7 --- /dev/null +++ b/db/version_set.h @@ -0,0 +1,383 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// The representation of a DBImpl consists of a set of Versions. The +// newest version is called "current". Older versions may be kept +// around to provide a consistent view to live iterators. +// +// Each Version keeps track of a set of Table files per level. The +// entire set of versions is maintained in a VersionSet. +// +// Version,VersionSet are thread-compatible, but require external +// synchronization on all accesses. + +#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ +#define STORAGE_LEVELDB_DB_VERSION_SET_H_ + +#include +#include +#include +#include "db/dbformat.h" +#include "db/version_edit.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +namespace log { class Writer; } + +class Compaction; +class Iterator; +class MemTable; +class TableBuilder; +class TableCache; +class Version; +class VersionSet; +class WritableFile; + +// Return the smallest index i such that files[i]->largest >= key. +// Return files.size() if there is no such file. +// REQUIRES: "files" contains a sorted list of non-overlapping files. +extern int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key); + +// Returns true iff some file in "files" overlaps the user key range +// [*smallest,*largest]. +// smallest==NULL represents a key smaller than all keys in the DB. +// largest==NULL represents a key largest than all keys in the DB. +// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges +// in sorted order. +extern bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key); + +class Version { + public: + // Append to *iters a sequence of iterators that will + // yield the contents of this Version when merged together. + // REQUIRES: This version has been saved (see VersionSet::SaveTo) + void AddIterators(const ReadOptions&, std::vector* iters); + + // Lookup the value for key. If found, store it in *val and + // return OK. Else return a non-OK status. Fills *stats. + // REQUIRES: lock is not held + struct GetStats { + FileMetaData* seek_file; + int seek_file_level; + }; + Status Get(const ReadOptions&, const LookupKey& key, std::string* val, + GetStats* stats); + + // Adds "stats" into the current state. Returns true if a new + // compaction may need to be triggered, false otherwise. + // REQUIRES: lock is held + bool UpdateStats(const GetStats& stats); + + // Reference count management (so Versions do not disappear out from + // under live iterators) + void Ref(); + void Unref(); + + void GetOverlappingInputs( + int level, + const InternalKey* begin, // NULL means before all keys + const InternalKey* end, // NULL means after all keys + std::vector* inputs); + + // Returns true iff some file in the specified level overlaps + // some part of [*smallest_user_key,*largest_user_key]. + // smallest_user_key==NULL represents a key smaller than all keys in the DB. + // largest_user_key==NULL represents a key largest than all keys in the DB. + bool OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key); + + // Return the level at which we should place a new memtable compaction + // result that covers the range [smallest_user_key,largest_user_key]. + int PickLevelForMemTableOutput(const Slice& smallest_user_key, + const Slice& largest_user_key); + + int NumFiles(int level) const { return files_[level].size(); } + + // Return a human readable string that describes this version's contents. + std::string DebugString() const; + + private: + friend class Compaction; + friend class VersionSet; + + class LevelFileNumIterator; + Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; + + VersionSet* vset_; // VersionSet to which this Version belongs + Version* next_; // Next version in linked list + Version* prev_; // Previous version in linked list + int refs_; // Number of live refs to this version + + // List of files per level + std::vector files_[config::kNumLevels]; + + // Next file to compact based on seek stats. + FileMetaData* file_to_compact_; + int file_to_compact_level_; + + // Level that should be compacted next and its compaction score. + // Score < 1 means compaction is not strictly needed. These fields + // are initialized by Finalize(). + double compaction_score_; + int compaction_level_; + + explicit Version(VersionSet* vset) + : vset_(vset), next_(this), prev_(this), refs_(0), + file_to_compact_(NULL), + file_to_compact_level_(-1), + compaction_score_(-1), + compaction_level_(-1) { + } + + ~Version(); + + // No copying allowed + Version(const Version&); + void operator=(const Version&); +}; + +class VersionSet { + public: + VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator*); + ~VersionSet(); + + // Apply *edit to the current version to form a new descriptor that + // is both saved to persistent state and installed as the new + // current version. Will release *mu while actually writing to the file. + // REQUIRES: *mu is held on entry. + // REQUIRES: no other thread concurrently calls LogAndApply() + Status LogAndApply(VersionEdit* edit, port::Mutex* mu) + EXCLUSIVE_LOCKS_REQUIRED(mu); + + // Recover the last saved descriptor from persistent storage. + Status Recover(); + + // Return the current version. + Version* current() const { return current_; } + + // Return the current manifest file number + uint64_t ManifestFileNumber() const { return manifest_file_number_; } + + // Allocate and return a new file number + uint64_t NewFileNumber() { return next_file_number_++; } + + // Arrange to reuse "file_number" unless a newer file number has + // already been allocated. + // REQUIRES: "file_number" was returned by a call to NewFileNumber(). + void ReuseFileNumber(uint64_t file_number) { + if (next_file_number_ == file_number + 1) { + next_file_number_ = file_number; + } + } + + // Return the number of Table files at the specified level. + int NumLevelFiles(int level) const; + + // Return the combined file size of all files at the specified level. + int64_t NumLevelBytes(int level) const; + + // Return the last sequence number. + uint64_t LastSequence() const { return last_sequence_; } + + // Set the last sequence number to s. + void SetLastSequence(uint64_t s) { + assert(s >= last_sequence_); + last_sequence_ = s; + } + + // Mark the specified file number as used. + void MarkFileNumberUsed(uint64_t number); + + // Return the current log file number. + uint64_t LogNumber() const { return log_number_; } + + // Return the log file number for the log file that is currently + // being compacted, or zero if there is no such log file. + uint64_t PrevLogNumber() const { return prev_log_number_; } + + // Pick level and inputs for a new compaction. + // Returns NULL if there is no compaction to be done. + // Otherwise returns a pointer to a heap-allocated object that + // describes the compaction. Caller should delete the result. + Compaction* PickCompaction(); + + // Return a compaction object for compacting the range [begin,end] in + // the specified level. Returns NULL if there is nothing in that + // level that overlaps the specified range. Caller should delete + // the result. + Compaction* CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t MaxNextLevelOverlappingBytes(); + + // Create an iterator that reads over the compaction inputs for "*c". + // The caller should delete the iterator when no longer needed. + Iterator* MakeInputIterator(Compaction* c); + + // Returns true iff some level needs a compaction. + bool NeedsCompaction() const { + Version* v = current_; + return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL); + } + + // Add all files listed in any live version to *live. + // May also mutate some internal state. + void AddLiveFiles(std::set* live); + + // Return the approximate offset in the database of the data for + // "key" as of version "v". + uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); + + // Return a human-readable short (single-line) summary of the number + // of files per level. Uses *scratch as backing store. + struct LevelSummaryStorage { + char buffer[100]; + }; + const char* LevelSummary(LevelSummaryStorage* scratch) const; + + private: + class Builder; + + friend class Compaction; + friend class Version; + + void Finalize(Version* v); + + void GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest); + + void GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest); + + void SetupOtherInputs(Compaction* c); + + // Save current contents to *log + Status WriteSnapshot(log::Writer* log); + + void AppendVersion(Version* v); + + bool ManifestContains(const std::string& record) const; + + Env* const env_; + const std::string dbname_; + const Options* const options_; + TableCache* const table_cache_; + const InternalKeyComparator icmp_; + uint64_t next_file_number_; + uint64_t manifest_file_number_; + uint64_t last_sequence_; + uint64_t log_number_; + uint64_t prev_log_number_; // 0 or backing store for memtable being compacted + + // Opened lazily + WritableFile* descriptor_file_; + log::Writer* descriptor_log_; + Version dummy_versions_; // Head of circular doubly-linked list of versions. + Version* current_; // == dummy_versions_.prev_ + + // Per-level key at which the next compaction at that level should start. + // Either an empty string, or a valid InternalKey. + std::string compact_pointer_[config::kNumLevels]; + + // No copying allowed + VersionSet(const VersionSet&); + void operator=(const VersionSet&); +}; + +// A Compaction encapsulates information about a compaction. +class Compaction { + public: + ~Compaction(); + + // Return the level that is being compacted. Inputs from "level" + // and "level+1" will be merged to produce a set of "level+1" files. + int level() const { return level_; } + + // Return the object that holds the edits to the descriptor done + // by this compaction. + VersionEdit* edit() { return &edit_; } + + // "which" must be either 0 or 1 + int num_input_files(int which) const { return inputs_[which].size(); } + + // Return the ith input file at "level()+which" ("which" must be 0 or 1). + FileMetaData* input(int which, int i) const { return inputs_[which][i]; } + + // Maximum size of files to build during this compaction. + uint64_t MaxOutputFileSize() const { return max_output_file_size_; } + + // Is this a trivial compaction that can be implemented by just + // moving a single input file to the next level (no merging or splitting) + bool IsTrivialMove() const; + + // Add all inputs to this compaction as delete operations to *edit. + void AddInputDeletions(VersionEdit* edit); + + // Returns true if the information we have available guarantees that + // the compaction is producing data in "level+1" for which no data exists + // in levels greater than "level+1". + bool IsBaseLevelForKey(const Slice& user_key); + + // Returns true iff we should stop building the current output + // before processing "internal_key". + bool ShouldStopBefore(const Slice& internal_key); + + // Release the input version for the compaction, once the compaction + // is successful. + void ReleaseInputs(); + + private: + friend class Version; + friend class VersionSet; + + explicit Compaction(int level); + + int level_; + uint64_t max_output_file_size_; + Version* input_version_; + VersionEdit edit_; + + // Each compaction reads inputs from "level_" and "level_+1" + std::vector inputs_[2]; // The two sets of inputs + + // State used to check for number of of overlapping grandparent files + // (parent == level_ + 1, grandparent == level_ + 2) + std::vector grandparents_; + size_t grandparent_index_; // Index in grandparent_starts_ + bool seen_key_; // Some output key has been seen + int64_t overlapped_bytes_; // Bytes of overlap between current output + // and grandparent files + + // State for implementing IsBaseLevelForKey + + // level_ptrs_ holds indices into input_version_->levels_: our state + // is that we are positioned at one of the file ranges for each + // higher level than the ones involved in this compaction (i.e. for + // all L >= level_ + 2). + size_t level_ptrs_[config::kNumLevels]; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/db/version_set_test.cc b/db/version_set_test.cc new file mode 100644 index 000000000..501e34d13 --- /dev/null +++ b/db/version_set_test.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class FindFileTest { + public: + std::vector files_; + bool disjoint_sorted_files_; + + FindFileTest() : disjoint_sorted_files_(true) { } + + ~FindFileTest() { + for (int i = 0; i < files_.size(); i++) { + delete files_[i]; + } + } + + void Add(const char* smallest, const char* largest, + SequenceNumber smallest_seq = 100, + SequenceNumber largest_seq = 100) { + FileMetaData* f = new FileMetaData; + f->number = files_.size() + 1; + f->smallest = InternalKey(smallest, smallest_seq, kTypeValue); + f->largest = InternalKey(largest, largest_seq, kTypeValue); + files_.push_back(f); + } + + int Find(const char* key) { + InternalKey target(key, 100, kTypeValue); + InternalKeyComparator cmp(BytewiseComparator()); + return FindFile(cmp, files_, target.Encode()); + } + + bool Overlaps(const char* smallest, const char* largest) { + InternalKeyComparator cmp(BytewiseComparator()); + Slice s(smallest != NULL ? smallest : ""); + Slice l(largest != NULL ? largest : ""); + return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_, + (smallest != NULL ? &s : NULL), + (largest != NULL ? &l : NULL)); + } +}; + +TEST(FindFileTest, Empty) { + ASSERT_EQ(0, Find("foo")); + ASSERT_TRUE(! Overlaps("a", "z")); + ASSERT_TRUE(! Overlaps(NULL, "z")); + ASSERT_TRUE(! Overlaps("a", NULL)); + ASSERT_TRUE(! Overlaps(NULL, NULL)); +} + +TEST(FindFileTest, Single) { + Add("p", "q"); + ASSERT_EQ(0, Find("a")); + ASSERT_EQ(0, Find("p")); + ASSERT_EQ(0, Find("p1")); + ASSERT_EQ(0, Find("q")); + ASSERT_EQ(1, Find("q1")); + ASSERT_EQ(1, Find("z")); + + ASSERT_TRUE(! Overlaps("a", "b")); + ASSERT_TRUE(! Overlaps("z1", "z2")); + ASSERT_TRUE(Overlaps("a", "p")); + ASSERT_TRUE(Overlaps("a", "q")); + ASSERT_TRUE(Overlaps("a", "z")); + ASSERT_TRUE(Overlaps("p", "p1")); + ASSERT_TRUE(Overlaps("p", "q")); + ASSERT_TRUE(Overlaps("p", "z")); + ASSERT_TRUE(Overlaps("p1", "p2")); + ASSERT_TRUE(Overlaps("p1", "z")); + ASSERT_TRUE(Overlaps("q", "q")); + ASSERT_TRUE(Overlaps("q", "q1")); + + ASSERT_TRUE(! Overlaps(NULL, "j")); + ASSERT_TRUE(! Overlaps("r", NULL)); + ASSERT_TRUE(Overlaps(NULL, "p")); + ASSERT_TRUE(Overlaps(NULL, "p1")); + ASSERT_TRUE(Overlaps("q", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); +} + + +TEST(FindFileTest, Multiple) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_EQ(0, Find("100")); + ASSERT_EQ(0, Find("150")); + ASSERT_EQ(0, Find("151")); + ASSERT_EQ(0, Find("199")); + ASSERT_EQ(0, Find("200")); + ASSERT_EQ(1, Find("201")); + ASSERT_EQ(1, Find("249")); + ASSERT_EQ(1, Find("250")); + ASSERT_EQ(2, Find("251")); + ASSERT_EQ(2, Find("299")); + ASSERT_EQ(2, Find("300")); + ASSERT_EQ(2, Find("349")); + ASSERT_EQ(2, Find("350")); + ASSERT_EQ(3, Find("351")); + ASSERT_EQ(3, Find("400")); + ASSERT_EQ(3, Find("450")); + ASSERT_EQ(4, Find("451")); + + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("251", "299")); + ASSERT_TRUE(! Overlaps("451", "500")); + ASSERT_TRUE(! Overlaps("351", "399")); + + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); +} + +TEST(FindFileTest, MultipleNullBoundaries) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_TRUE(! Overlaps(NULL, "149")); + ASSERT_TRUE(! Overlaps("451", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); + ASSERT_TRUE(Overlaps(NULL, "150")); + ASSERT_TRUE(Overlaps(NULL, "199")); + ASSERT_TRUE(Overlaps(NULL, "200")); + ASSERT_TRUE(Overlaps(NULL, "201")); + ASSERT_TRUE(Overlaps(NULL, "400")); + ASSERT_TRUE(Overlaps(NULL, "800")); + ASSERT_TRUE(Overlaps("100", NULL)); + ASSERT_TRUE(Overlaps("200", NULL)); + ASSERT_TRUE(Overlaps("449", NULL)); + ASSERT_TRUE(Overlaps("450", NULL)); +} + +TEST(FindFileTest, OverlapSequenceChecks) { + Add("200", "200", 5000, 3000); + ASSERT_TRUE(! Overlaps("199", "199")); + ASSERT_TRUE(! Overlaps("201", "300")); + ASSERT_TRUE(Overlaps("200", "200")); + ASSERT_TRUE(Overlaps("190", "200")); + ASSERT_TRUE(Overlaps("200", "210")); +} + +TEST(FindFileTest, OverlappingFiles) { + Add("150", "600"); + Add("400", "500"); + disjoint_sorted_files_ = false; + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("601", "700")); + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); + ASSERT_TRUE(Overlaps("450", "700")); + ASSERT_TRUE(Overlaps("600", "700")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/write_batch.cc b/db/write_batch.cc new file mode 100644 index 000000000..33f4a4257 --- /dev/null +++ b/db/write_batch.cc @@ -0,0 +1,147 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch::rep_ := +// sequence: fixed64 +// count: fixed32 +// data: record[count] +// record := +// kTypeValue varstring varstring | +// kTypeDeletion varstring +// varstring := +// len: varint32 +// data: uint8[len] + +#include "leveldb/write_batch.h" + +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "util/coding.h" + +namespace leveldb { + +// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. +static const size_t kHeader = 12; + +WriteBatch::WriteBatch() { + Clear(); +} + +WriteBatch::~WriteBatch() { } + +WriteBatch::Handler::~Handler() { } + +void WriteBatch::Clear() { + rep_.clear(); + rep_.resize(kHeader); +} + +Status WriteBatch::Iterate(Handler* handler) const { + Slice input(rep_); + if (input.size() < kHeader) { + return Status::Corruption("malformed WriteBatch (too small)"); + } + + input.remove_prefix(kHeader); + Slice key, value; + int found = 0; + while (!input.empty()) { + found++; + char tag = input[0]; + input.remove_prefix(1); + switch (tag) { + case kTypeValue: + if (GetLengthPrefixedSlice(&input, &key) && + GetLengthPrefixedSlice(&input, &value)) { + handler->Put(key, value); + } else { + return Status::Corruption("bad WriteBatch Put"); + } + break; + case kTypeDeletion: + if (GetLengthPrefixedSlice(&input, &key)) { + handler->Delete(key); + } else { + return Status::Corruption("bad WriteBatch Delete"); + } + break; + default: + return Status::Corruption("unknown WriteBatch tag"); + } + } + if (found != WriteBatchInternal::Count(this)) { + return Status::Corruption("WriteBatch has wrong count"); + } else { + return Status::OK(); + } +} + +int WriteBatchInternal::Count(const WriteBatch* b) { + return DecodeFixed32(b->rep_.data() + 8); +} + +void WriteBatchInternal::SetCount(WriteBatch* b, int n) { + EncodeFixed32(&b->rep_[8], n); +} + +SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { + return SequenceNumber(DecodeFixed64(b->rep_.data())); +} + +void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { + EncodeFixed64(&b->rep_[0], seq); +} + +void WriteBatch::Put(const Slice& key, const Slice& value) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeValue)); + PutLengthPrefixedSlice(&rep_, key); + PutLengthPrefixedSlice(&rep_, value); +} + +void WriteBatch::Delete(const Slice& key) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeDeletion)); + PutLengthPrefixedSlice(&rep_, key); +} + +namespace { +class MemTableInserter : public WriteBatch::Handler { + public: + SequenceNumber sequence_; + MemTable* mem_; + + virtual void Put(const Slice& key, const Slice& value) { + mem_->Add(sequence_, kTypeValue, key, value); + sequence_++; + } + virtual void Delete(const Slice& key) { + mem_->Add(sequence_, kTypeDeletion, key, Slice()); + sequence_++; + } +}; +} // namespace + +Status WriteBatchInternal::InsertInto(const WriteBatch* b, + MemTable* memtable) { + MemTableInserter inserter; + inserter.sequence_ = WriteBatchInternal::Sequence(b); + inserter.mem_ = memtable; + return b->Iterate(&inserter); +} + +void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { + assert(contents.size() >= kHeader); + b->rep_.assign(contents.data(), contents.size()); +} + +void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { + SetCount(dst, Count(dst) + Count(src)); + assert(src->rep_.size() >= kHeader); + dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); +} + +} // namespace leveldb diff --git a/db/write_batch_internal.h b/db/write_batch_internal.h new file mode 100644 index 000000000..4423a7f31 --- /dev/null +++ b/db/write_batch_internal.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ +#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ + +#include "leveldb/write_batch.h" + +namespace leveldb { + +class MemTable; + +// WriteBatchInternal provides static methods for manipulating a +// WriteBatch that we don't want in the public WriteBatch interface. +class WriteBatchInternal { + public: + // Return the number of entries in the batch. + static int Count(const WriteBatch* batch); + + // Set the count for the number of entries in the batch. + static void SetCount(WriteBatch* batch, int n); + + // Return the seqeunce number for the start of this batch. + static SequenceNumber Sequence(const WriteBatch* batch); + + // Store the specified number as the seqeunce number for the start of + // this batch. + static void SetSequence(WriteBatch* batch, SequenceNumber seq); + + static Slice Contents(const WriteBatch* batch) { + return Slice(batch->rep_); + } + + static size_t ByteSize(const WriteBatch* batch) { + return batch->rep_.size(); + } + + static void SetContents(WriteBatch* batch, const Slice& contents); + + static Status InsertInto(const WriteBatch* batch, MemTable* memtable); + + static void Append(WriteBatch* dst, const WriteBatch* src); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/db/write_batch_test.cc b/db/write_batch_test.cc new file mode 100644 index 000000000..9064e3d85 --- /dev/null +++ b/db/write_batch_test.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string PrintContents(WriteBatch* b) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* mem = new MemTable(cmp); + mem->Ref(); + std::string state; + Status s = WriteBatchInternal::InsertInto(b, mem); + int count = 0; + Iterator* iter = mem->NewIterator(); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey ikey; + ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey)); + switch (ikey.type) { + case kTypeValue: + state.append("Put("); + state.append(ikey.user_key.ToString()); + state.append(", "); + state.append(iter->value().ToString()); + state.append(")"); + count++; + break; + case kTypeDeletion: + state.append("Delete("); + state.append(ikey.user_key.ToString()); + state.append(")"); + count++; + break; + } + state.append("@"); + state.append(NumberToString(ikey.sequence)); + } + delete iter; + if (!s.ok()) { + state.append("ParseError()"); + } else if (count != WriteBatchInternal::Count(b)) { + state.append("CountMismatch()"); + } + mem->Unref(); + return state; +} + +class WriteBatchTest { }; + +TEST(WriteBatchTest, Empty) { + WriteBatch batch; + ASSERT_EQ("", PrintContents(&batch)); + ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); +} + +TEST(WriteBatchTest, Multiple) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + batch.Put(Slice("baz"), Slice("boo")); + WriteBatchInternal::SetSequence(&batch, 100); + ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch)); + ASSERT_EQ(3, WriteBatchInternal::Count(&batch)); + ASSERT_EQ("Put(baz, boo)@102" + "Delete(box)@101" + "Put(foo, bar)@100", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Corruption) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + WriteBatchInternal::SetSequence(&batch, 200); + Slice contents = WriteBatchInternal::Contents(&batch); + WriteBatchInternal::SetContents(&batch, + Slice(contents.data(),contents.size()-1)); + ASSERT_EQ("Put(foo, bar)@200" + "ParseError()", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Append) { + WriteBatch b1, b2; + WriteBatchInternal::SetSequence(&b1, 200); + WriteBatchInternal::SetSequence(&b2, 300); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("", + PrintContents(&b1)); + b2.Put("a", "va"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200", + PrintContents(&b1)); + b2.Clear(); + b2.Put("b", "vb"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@201", + PrintContents(&b1)); + b2.Delete("foo"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@202" + "Put(b, vb)@201" + "Delete(foo)@203", + PrintContents(&b1)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/doc/bench/db_bench_sqlite3.cc b/doc/bench/db_bench_sqlite3.cc new file mode 100644 index 000000000..e63aaa8dc --- /dev/null +++ b/doc/bench/db_bench_sqlite3.cc @@ -0,0 +1,718 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "util/histogram.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// +// fillseq -- write N values in sequential key order in async mode +// fillseqsync -- write N/100 values in sequential key order in sync mode +// fillseqbatch -- batch write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// fillrandsync -- write N/100 values in random key order in sync mode +// fillrandbatch -- batch write N values in sequential key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillrand100K -- write N/1000 100K values in random order in async mode +// fillseq100K -- write N/1000 100K values in sequential order in async mode +// readseq -- read N times sequentially +// readrandom -- read N times in random order +// readrand100K -- read N/1000 100K values in sequential order in async mode +static const char* FLAGS_benchmarks = + "fillseq," + "fillseqsync," + "fillseqbatch," + "fillrandom," + "fillrandsync," + "fillrandbatch," + "overwrite," + "overwritebatch," + "readrandom," + "readseq," + "fillrand100K," + "fillseq100K," + "readseq," + "readrand100K," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Page size. Default 1 KB. +static int FLAGS_page_size = 1024; + +// Number of pages. +// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB. +static int FLAGS_num_pages = 4096; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// If true, we allow batch writes to occur +static bool FLAGS_transaction = true; + +// If true, we enable Write-Ahead Logging +static bool FLAGS_WAL_enabled = true; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +inline +static void ExecErrorCheck(int status, char *err_msg) { + if (status != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", err_msg); + sqlite3_free(err_msg); + exit(1); + } +} + +inline +static void StepErrorCheck(int status) { + if (status != SQLITE_DONE) { + fprintf(stderr, "SQL step error: status = %d\n", status); + exit(1); + } +} + +inline +static void ErrorCheck(int status) { + if (status != SQLITE_OK) { + fprintf(stderr, "sqlite3 error: status = %d\n", status); + exit(1); + } +} + +inline +static void WalCheckpoint(sqlite3* db_) { + // Flush all writes to disk + if (FLAGS_WAL_enabled) { + sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL); + } +} + +namespace leveldb { + +// Helper for quickly generating random data. +namespace { +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +} // namespace + +class Benchmark { + private: + sqlite3* db_; + int db_num_; + int num_; + int reads_; + double start_; + double last_op_finish_; + int64_t bytes_; + std::string message_; + Histogram hist_; + RandomGenerator gen_; + Random rand_; + + // State kept for progress messages + int done_; + int next_report_; // When to report next + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + } + + void PrintEnvironment() { + fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + void Start() { + start_ = Env::Default()->NowMicros() * 1e-6; + bytes_ = 0; + message_.clear(); + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + next_report_ = 100; + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros() * 1e-6; + double micros = (now - last_op_finish_) * 1e6; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void Stop(const Slice& name) { + double finish = Env::Default()->NowMicros() * 1e-6; + + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + if (bytes_ > 0) { + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / (finish - start_)); + if (!message_.empty()) { + message_ = std::string(rate) + " " + message_; + } else { + message_ = rate; + } + } + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + (finish - start_) * 1e6 / done_, + (message_.empty() ? "" : " "), + message_.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } + + public: + enum Order { + SEQUENTIAL, + RANDOM + }; + enum DBState { + FRESH, + EXISTING + }; + + Benchmark() + : db_(NULL), + db_num_(0), + num_(FLAGS_num), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + bytes_(0), + rand_(301) { + std::vector files; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + Env::Default()->GetChildren(test_dir, &files); + if (!FLAGS_use_existing_db) { + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("dbbench_sqlite3")) { + std::string file_name(test_dir); + file_name += "/"; + file_name += files[i]; + Env::Default()->DeleteFile(file_name.c_str()); + } + } + } + } + + ~Benchmark() { + int status = sqlite3_close(db_); + ErrorCheck(status); + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + bytes_ = 0; + Start(); + + bool known = true; + bool write_sync = false; + if (name == Slice("fillseq")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseqbatch")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("fillrandom")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillrandbatch")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("overwrite")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("overwritebatch")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("fillrandsync")) { + write_sync = true; + Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseqsync")) { + write_sync = true; + Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillrand100K")) { + Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseq100K")) { + Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); + WalCheckpoint(db_); + } else if (name == Slice("readseq")) { + ReadSequential(); + } else if (name == Slice("readrandom")) { + Read(RANDOM, 1); + } else if (name == Slice("readrand100K")) { + int n = reads_; + reads_ /= 1000; + Read(RANDOM, 1); + reads_ = n; + } else { + known = false; + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + if (known) { + Stop(name); + } + } + } + + void Open() { + assert(db_ == NULL); + + int status; + char file_name[100]; + char* err_msg = NULL; + db_num_++; + + // Open database + std::string tmp_dir; + Env::Default()->GetTestDirectory(&tmp_dir); + snprintf(file_name, sizeof(file_name), + "%s/dbbench_sqlite3-%d.db", + tmp_dir.c_str(), + db_num_); + status = sqlite3_open(file_name, &db_); + if (status) { + fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_)); + exit(1); + } + + // Change SQLite cache size + char cache_size[100]; + snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d", + FLAGS_num_pages); + status = sqlite3_exec(db_, cache_size, NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + + // FLAGS_page_size is defaulted to 1024 + if (FLAGS_page_size != 1024) { + char page_size[100]; + snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d", + FLAGS_page_size); + status = sqlite3_exec(db_, page_size, NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + + // Change journal mode to WAL if WAL enabled flag is on + if (FLAGS_WAL_enabled) { + std::string WAL_stmt = "PRAGMA journal_mode = WAL"; + + // LevelDB's default cache size is a combined 4 MB + std::string WAL_checkpoint = "PRAGMA wal_autocheckpoint = 4096"; + status = sqlite3_exec(db_, WAL_stmt.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + status = sqlite3_exec(db_, WAL_checkpoint.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + + // Change locking mode to exclusive and create tables/index for database + std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE"; + std::string create_stmt = + "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))"; + std::string stmt_array[] = { locking_stmt, create_stmt }; + int stmt_array_length = sizeof(stmt_array) / sizeof(std::string); + for (int i = 0; i < stmt_array_length; i++) { + status = sqlite3_exec(db_, stmt_array[i].c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + } + + void Write(bool write_sync, Order order, DBState state, + int num_entries, int value_size, int entries_per_batch) { + // Create new database if state == FRESH + if (state == FRESH) { + if (FLAGS_use_existing_db) { + message_ = "skipping (--use_existing_db is true)"; + return; + } + sqlite3_close(db_); + db_ = NULL; + Open(); + Start(); + } + + if (num_entries != num_) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_entries); + message_ = msg; + } + + char* err_msg = NULL; + int status; + + sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt; + std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)"; + std::string begin_trans_str = "BEGIN TRANSACTION;"; + std::string end_trans_str = "END TRANSACTION;"; + + // Check for synchronous flag in options + std::string sync_stmt = (write_sync) ? "PRAGMA synchronous = FULL" : + "PRAGMA synchronous = OFF"; + status = sqlite3_exec(db_, sync_stmt.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + + // Preparing sqlite3 statements + status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, + &replace_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, + &begin_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, + &end_trans_stmt, NULL); + ErrorCheck(status); + + bool transaction = (entries_per_batch > 1); + for (int i = 0; i < num_entries; i += entries_per_batch) { + // Begin write transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(begin_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(begin_trans_stmt); + ErrorCheck(status); + } + + // Create and execute SQL statements + for (int j = 0; j < entries_per_batch; j++) { + const char* value = gen_.Generate(value_size).data(); + + // Create values for key-value pair + const int k = (order == SEQUENTIAL) ? i + j : + (rand_.Next() % num_entries); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + + // Bind KV values into replace_stmt + status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC); + ErrorCheck(status); + status = sqlite3_bind_blob(replace_stmt, 2, value, + value_size, SQLITE_STATIC); + ErrorCheck(status); + + // Execute replace_stmt + bytes_ += value_size + strlen(key); + status = sqlite3_step(replace_stmt); + StepErrorCheck(status); + + // Reset SQLite statement for another use + status = sqlite3_clear_bindings(replace_stmt); + ErrorCheck(status); + status = sqlite3_reset(replace_stmt); + ErrorCheck(status); + + FinishedSingleOp(); + } + + // End write transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(end_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(end_trans_stmt); + ErrorCheck(status); + } + } + + status = sqlite3_finalize(replace_stmt); + ErrorCheck(status); + status = sqlite3_finalize(begin_trans_stmt); + ErrorCheck(status); + status = sqlite3_finalize(end_trans_stmt); + ErrorCheck(status); + } + + void Read(Order order, int entries_per_batch) { + int status; + sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt; + + std::string read_str = "SELECT * FROM test WHERE key = ?"; + std::string begin_trans_str = "BEGIN TRANSACTION;"; + std::string end_trans_str = "END TRANSACTION;"; + + // Preparing sqlite3 statements + status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, + &begin_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, + &end_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, NULL); + ErrorCheck(status); + + bool transaction = (entries_per_batch > 1); + for (int i = 0; i < reads_; i += entries_per_batch) { + // Begin read transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(begin_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(begin_trans_stmt); + ErrorCheck(status); + } + + // Create and execute SQL statements + for (int j = 0; j < entries_per_batch; j++) { + // Create key value + char key[100]; + int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_); + snprintf(key, sizeof(key), "%016d", k); + + // Bind key value into read_stmt + status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC); + ErrorCheck(status); + + // Execute read statement + while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {} + StepErrorCheck(status); + + // Reset SQLite statement for another use + status = sqlite3_clear_bindings(read_stmt); + ErrorCheck(status); + status = sqlite3_reset(read_stmt); + ErrorCheck(status); + FinishedSingleOp(); + } + + // End read transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(end_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(end_trans_stmt); + ErrorCheck(status); + } + } + + status = sqlite3_finalize(read_stmt); + ErrorCheck(status); + status = sqlite3_finalize(begin_trans_stmt); + ErrorCheck(status); + status = sqlite3_finalize(end_trans_stmt); + ErrorCheck(status); + } + + void ReadSequential() { + int status; + sqlite3_stmt *pStmt; + std::string read_str = "SELECT * FROM test ORDER BY key"; + + status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, NULL); + ErrorCheck(status); + for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) { + bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2); + FinishedSingleOp(); + } + + status = sqlite3_finalize(pStmt); + ErrorCheck(status); + } + +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + std::string default_db_path; + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_use_existing_db = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) { + FLAGS_transaction = false; + } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { + FLAGS_page_size = n; + } else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) { + FLAGS_num_pages = n; + } else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_WAL_enabled = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/doc/bench/db_bench_tree_db.cc b/doc/bench/db_bench_tree_db.cc new file mode 100644 index 000000000..ed86f031c --- /dev/null +++ b/doc/bench/db_bench_tree_db.cc @@ -0,0 +1,528 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "util/histogram.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillseqsync -- write N/100 values in sequential key order in sync mode +// fillrandsync -- write N/100 values in random key order in sync mode +// fillrand100K -- write N/1000 100K values in random order in async mode +// fillseq100K -- write N/1000 100K values in seq order in async mode +// readseq -- read N times sequentially +// readseq100K -- read N/1000 100K values in sequential order in async mode +// readrand100K -- read N/1000 100K values in sequential order in async mode +// readrandom -- read N times in random order +static const char* FLAGS_benchmarks = + "fillseq," + "fillseqsync," + "fillrandsync," + "fillrandom," + "overwrite," + "readrandom," + "readseq," + "fillrand100K," + "fillseq100K," + "readseq100K," + "readrand100K," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Cache size. Default 4 MB +static int FLAGS_cache_size = 4194304; + +// Page size. Default 1 KB +static int FLAGS_page_size = 1024; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// Compression flag. If true, compression is on. If false, compression +// is off. +static bool FLAGS_compression = true; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +inline +static void DBSynchronize(kyotocabinet::TreeDB* db_) +{ + // Synchronize will flush writes to disk + if (!db_->synchronize()) { + fprintf(stderr, "synchronize error: %s\n", db_->error().name()); + } +} + +namespace leveldb { + +// Helper for quickly generating random data. +namespace { +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +} // namespace + +class Benchmark { + private: + kyotocabinet::TreeDB* db_; + int db_num_; + int num_; + int reads_; + double start_; + double last_op_finish_; + int64_t bytes_; + std::string message_; + Histogram hist_; + RandomGenerator gen_; + Random rand_; + kyotocabinet::LZOCompressor comp_; + + // State kept for progress messages + int done_; + int next_report_; // When to report next + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + } + + void PrintEnvironment() { + fprintf(stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n", + kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + void Start() { + start_ = Env::Default()->NowMicros() * 1e-6; + bytes_ = 0; + message_.clear(); + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + next_report_ = 100; + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros() * 1e-6; + double micros = (now - last_op_finish_) * 1e6; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void Stop(const Slice& name) { + double finish = Env::Default()->NowMicros() * 1e-6; + + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + if (bytes_ > 0) { + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / (finish - start_)); + if (!message_.empty()) { + message_ = std::string(rate) + " " + message_; + } else { + message_ = rate; + } + } + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + (finish - start_) * 1e6 / done_, + (message_.empty() ? "" : " "), + message_.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } + + public: + enum Order { + SEQUENTIAL, + RANDOM + }; + enum DBState { + FRESH, + EXISTING + }; + + Benchmark() + : db_(NULL), + num_(FLAGS_num), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + bytes_(0), + rand_(301) { + std::vector files; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + Env::Default()->GetChildren(test_dir.c_str(), &files); + if (!FLAGS_use_existing_db) { + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("dbbench_polyDB")) { + std::string file_name(test_dir); + file_name += "/"; + file_name += files[i]; + Env::Default()->DeleteFile(file_name.c_str()); + } + } + } + } + + ~Benchmark() { + if (!db_->close()) { + fprintf(stderr, "close error: %s\n", db_->error().name()); + } + } + + void Run() { + PrintHeader(); + Open(false); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + Start(); + + bool known = true; + bool write_sync = false; + if (name == Slice("fillseq")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); + + } else if (name == Slice("fillrandom")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("overwrite")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrandsync")) { + write_sync = true; + Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillseqsync")) { + write_sync = true; + Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrand100K")) { + Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); + DBSynchronize(db_); + } else if (name == Slice("fillseq100K")) { + Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); + DBSynchronize(db_); + } else if (name == Slice("readseq")) { + ReadSequential(); + } else if (name == Slice("readrandom")) { + ReadRandom(); + } else if (name == Slice("readrand100K")) { + int n = reads_; + reads_ /= 1000; + ReadRandom(); + reads_ = n; + } else if (name == Slice("readseq100K")) { + int n = reads_; + reads_ /= 1000; + ReadSequential(); + reads_ = n; + } else { + known = false; + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + if (known) { + Stop(name); + } + } + } + + private: + void Open(bool sync) { + assert(db_ == NULL); + + // Initialize db_ + db_ = new kyotocabinet::TreeDB(); + char file_name[100]; + db_num_++; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + snprintf(file_name, sizeof(file_name), + "%s/dbbench_polyDB-%d.kct", + test_dir.c_str(), + db_num_); + + // Create tuning options and open the database + int open_options = kyotocabinet::PolyDB::OWRITER | + kyotocabinet::PolyDB::OCREATE; + int tune_options = kyotocabinet::TreeDB::TSMALL | + kyotocabinet::TreeDB::TLINEAR; + if (FLAGS_compression) { + tune_options |= kyotocabinet::TreeDB::TCOMPRESS; + db_->tune_compressor(&comp_); + } + db_->tune_options(tune_options); + db_->tune_page_cache(FLAGS_cache_size); + db_->tune_page(FLAGS_page_size); + db_->tune_map(256LL<<20); + if (sync) { + open_options |= kyotocabinet::PolyDB::OAUTOSYNC; + } + if (!db_->open(file_name, open_options)) { + fprintf(stderr, "open error: %s\n", db_->error().name()); + } + } + + void Write(bool sync, Order order, DBState state, + int num_entries, int value_size, int entries_per_batch) { + // Create new database if state == FRESH + if (state == FRESH) { + if (FLAGS_use_existing_db) { + message_ = "skipping (--use_existing_db is true)"; + return; + } + delete db_; + db_ = NULL; + Open(sync); + Start(); // Do not count time taken to destroy/open + } + + if (num_entries != num_) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_entries); + message_ = msg; + } + + // Write to database + for (int i = 0; i < num_entries; i++) + { + const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + bytes_ += value_size + strlen(key); + std::string cpp_key = key; + if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) { + fprintf(stderr, "set error: %s\n", db_->error().name()); + } + FinishedSingleOp(); + } + } + + void ReadSequential() { + kyotocabinet::DB::Cursor* cur = db_->cursor(); + cur->jump(); + std::string ckey, cvalue; + while (cur->get(&ckey, &cvalue, true)) { + bytes_ += ckey.size() + cvalue.size(); + FinishedSingleOp(); + } + delete cur; + } + + void ReadRandom() { + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = rand_.Next() % reads_; + snprintf(key, sizeof(key), "%016d", k); + db_->get(key, &value); + FinishedSingleOp(); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + std::string default_db_path; + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { + FLAGS_page_size = n; + } else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_compression = (n == 1) ? true : false; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/doc/benchmark.html b/doc/benchmark.html new file mode 100644 index 000000000..c4639772c --- /dev/null +++ b/doc/benchmark.html @@ -0,0 +1,459 @@ + + + +LevelDB Benchmarks + + + + +

LevelDB Benchmarks

+

Google, July 2011

+
+ +

In order to test LevelDB's performance, we benchmark it against other well-established database implementations. We compare LevelDB (revision 39) against SQLite3 (version 3.7.6.3) and Kyoto Cabinet's (version 1.2.67) TreeDB (a B+Tree based key-value store). We would like to acknowledge Scott Hess and Mikio Hirabayashi for their suggestions and contributions to the SQLite3 and Kyoto Cabinet benchmarks, respectively.

+ +

Benchmarks were all performed on a six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz. (Note that LevelDB uses at most two CPUs since the benchmarks are single threaded: one to run the benchmark, and one for background compactions.) We ran the benchmarks on two machines (with identical processors), one with an Ext3 file system and one with an Ext4 file system. The machine with the Ext3 file system has a SATA Hitachi HDS721050CLA362 hard drive. The machine with the Ext4 file system has a SATA Samsung HD502HJ hard drive. Both hard drives spin at 7200 RPM and have hard drive write-caching enabled (using `hdparm -W 1 [device]`). The numbers reported below are the median of three measurements.

+ +

Benchmark Source Code

+

We wrote benchmark tools for SQLite and Kyoto TreeDB based on LevelDB's db_bench. The code for each of the benchmarks resides here:

+ + +

Custom Build Specifications

+
    +
  • LevelDB: LevelDB was compiled with the tcmalloc library and the Snappy compression library (revision 33). Assertions were disabled.
  • +
  • TreeDB: TreeDB was compiled using the LZO compression library (version 2.03). Furthermore, we enabled the TSMALL and TLINEAR options when opening the database in order to reduce the footprint of each record.
  • +
  • SQLite: We tuned SQLite's performance, by setting its locking mode to exclusive. We also enabled SQLite's write-ahead logging.
  • +
+ +

1. Baseline Performance

+

This section gives the baseline performance of all the +databases. Following sections show how performance changes as various +parameters are varied. For the baseline:

+
    +
  • Each database is allowed 4 MB of cache memory.
  • +
  • Databases are opened in asynchronous write mode. + (LevelDB's sync option, TreeDB's OAUTOSYNC option, and + SQLite3's synchronous options are all turned off). I.e., + every write is pushed to the operating system, but the + benchmark does not wait for the write to reach the disk.
  • +
  • Keys are 16 bytes each.
  • +
  • Value are 100 bytes each (with enough redundancy so that + a simple compressor shrinks them to 50% of their original + size).
  • +
  • Sequential reads/writes traverse the key space in increasing order.
  • +
  • Random reads/writes traverse the key space in random order.
  • +
+ +

A. Sequential Reads

+ + + + + + + + + + +
LevelDB4,030,000 ops/sec
 
Kyoto TreeDB1,010,000 ops/sec
 
SQLite3383,000 ops/sec
 
+

B. Random Reads

+ + + + + + + + + + +
LevelDB129,000 ops/sec
 
Kyoto TreeDB151,000 ops/sec
 
SQLite3134,000 ops/sec
 
+

C. Sequential Writes

+ + + + + + + + + + +
LevelDB779,000 ops/sec
 
Kyoto TreeDB342,000 ops/sec
 
SQLite348,600 ops/sec
 
+

D. Random Writes

+ + + + + + + + + + +
LevelDB164,000 ops/sec
 
Kyoto TreeDB88,500 ops/sec
 
SQLite39,860 ops/sec
 
+ +

LevelDB outperforms both SQLite3 and TreeDB in sequential and random write operations and sequential read operations. Kyoto Cabinet has the fastest random read operations.

+ +

2. Write Performance under Different Configurations

+

A. Large Values

+

For this benchmark, we start with an empty database, and write 100,000 byte values (~50% compressible). To keep the benchmark running time reasonable, we stop after writing 1000 values.

+

Sequential Writes

+ + + + + + + + + + +
LevelDB1,100 ops/sec
 
Kyoto TreeDB1,000 ops/sec
 
SQLite31,600 ops/sec
 
+

Random Writes

+ + + + + + + + + + +
LevelDB480 ops/sec
 
Kyoto TreeDB1,100 ops/sec
 
SQLite31,600 ops/sec
 
+

LevelDB doesn't perform as well with large values of 100,000 bytes each. This is because LevelDB writes keys and values at least twice: first time to the transaction log, and second time (during a compaction) to a sorted file. +With larger values, LevelDB's per-operation efficiency is swamped by the +cost of extra copies of large values.

+

B. Batch Writes

+

A batch write is a set of writes that are applied atomically to the underlying database. A single batch of N writes may be significantly faster than N individual writes. The following benchmark writes one thousand batches where each batch contains one thousand 100-byte values. TreeDB does not support batch writes and is omitted from this benchmark.

+

Sequential Writes

+ + + + + + + + + +
LevelDB840,000 entries/sec
 
(1.08x baseline)
SQLite3124,000 entries/sec
 
(2.55x baseline)
+

Random Writes

+ + + + + + + + + +
LevelDB221,000 entries/sec
 
(1.35x baseline)
SQLite322,000 entries/sec
 
(2.23x baseline)
+ +

Because of the way LevelDB persistent storage is organized, batches of +random writes are not much slower (only a factor of 4x) than batches +of sequential writes.

+ +

C. Synchronous Writes

+

In the following benchmark, we enable the synchronous writing modes +of all of the databases. Since this change significantly slows down the +benchmark, we stop after 10,000 writes. For synchronous write tests, we've +disabled hard drive write-caching (using `hdparm -W 0 [device]`).

+
    +
  • For LevelDB, we set WriteOptions.sync = true.
  • +
  • In TreeDB, we enabled TreeDB's OAUTOSYNC option.
  • +
  • For SQLite3, we set "PRAGMA synchronous = FULL".
  • +
+

Sequential Writes

+ + + + + + + + + + + + + +
LevelDB100 ops/sec
 
(0.003x baseline)
Kyoto TreeDB7 ops/sec
 
(0.0004x baseline)
SQLite388 ops/sec
 
(0.002x baseline)
+

Random Writes

+ + + + + + + + + + + + + +
LevelDB100 ops/sec
 
(0.015x baseline)
Kyoto TreeDB8 ops/sec
 
(0.001x baseline)
SQLite388 ops/sec
 
(0.009x baseline)
+ +

Also see the ext4 performance numbers below +since synchronous writes behave significantly differently +on ext3 and ext4.

+ +

D. Turning Compression Off

+ +

In the baseline measurements, LevelDB and TreeDB were using +light-weight compression +(Snappy for LevelDB, +and LZO for +TreeDB). SQLite3, by default does not use compression. The +experiments below show what happens when compression is disabled in +all of the databases (the SQLite3 numbers are just a copy of +its baseline measurements):

+ +

Sequential Writes

+ + + + + + + + + + + + + +
LevelDB594,000 ops/sec
 
(0.76x baseline)
Kyoto TreeDB485,000 ops/sec
 
(1.42x baseline)
SQLite348,600 ops/sec
 
(1.00x baseline)
+

Random Writes

+ + + + + + + + + + + + + +
LevelDB135,000 ops/sec
 
(0.82x baseline)
Kyoto TreeDB159,000 ops/sec
 
(1.80x baseline)
SQLite39,860 ops/sec
 
(1.00x baseline)
+ +

LevelDB's write performance is better with compression than without +since compression decreases the amount of data that has to be written +to disk. Therefore LevelDB users can leave compression enabled in +most scenarios without having worry about a tradeoff between space +usage and performance. TreeDB's performance on the other hand is +better without compression than with compression. Presumably this is +because TreeDB's compression library (LZO) is more expensive than +LevelDB's compression library (Snappy).

+ +

E. Using More Memory

+

We increased the overall cache size for each database to 128 MB. For LevelDB, we partitioned 128 MB into a 120 MB write buffer and 8 MB of cache (up from 2 MB of write buffer and 2 MB of cache). For SQLite3, we kept the page size at 1024 bytes, but increased the number of pages to 131,072 (up from 4096). For TreeDB, we also kept the page size at 1024 bytes, but increased the cache size to 128 MB (up from 4 MB).

+

Sequential Writes

+ + + + + + + + + + + + + +
LevelDB812,000 ops/sec
 
(1.04x baseline)
Kyoto TreeDB321,000 ops/sec
 
(0.94x baseline)
SQLite348,500 ops/sec
 
(1.00x baseline)
+

Random Writes

+ + + + + + + + + + + + + +
LevelDB355,000 ops/sec
 
(2.16x baseline)
Kyoto TreeDB284,000 ops/sec
 
(3.21x baseline)
SQLite39,670 ops/sec
 
(0.98x baseline)
+ +

SQLite's performance does not change substantially when compared to +the baseline, but the random write performance for both LevelDB and +TreeDB increases significantly. LevelDB's performance improves +because a larger write buffer reduces the need to merge sorted files +(since it creates a smaller number of larger sorted files). TreeDB's +performance goes up because the entire database is available in memory +for fast in-place updates.

+ +

3. Read Performance under Different Configurations

+

A. Larger Caches

+

We increased the overall memory usage to 128 MB for each database. +For LevelDB, we allocated 8 MB to LevelDB's write buffer and 120 MB +to LevelDB's cache. The other databases don't differentiate between a +write buffer and a cache, so we simply set their cache size to 128 +MB.

+

Sequential Reads

+ + + + + + + + + + + + + +
LevelDB5,210,000 ops/sec
 
(1.29x baseline)
Kyoto TreeDB1,070,000 ops/sec
 
(1.06x baseline)
SQLite3609,000 ops/sec
 
(1.59x baseline)
+ +

Random Reads

+ + + + + + + + + + + + + +
LevelDB190,000 ops/sec
 
(1.47x baseline)
Kyoto TreeDB463,000 ops/sec
 
(3.07x baseline)
SQLite3186,000 ops/sec
 
(1.39x baseline)
+ +

As expected, the read performance of all of the databases increases +when the caches are enlarged. In particular, TreeDB seems to make +very effective use of a cache that is large enough to hold the entire +database.

+ +

B. No Compression Reads

+

For this benchmark, we populated a database with 1 million entries consisting of 16 byte keys and 100 byte values. We compiled LevelDB and Kyoto Cabinet without compression support, so results that are read out from the database are already uncompressed. We've listed the SQLite3 baseline read performance as a point of comparison.

+

Sequential Reads

+ + + + + + + + + + + + + +
LevelDB4,880,000 ops/sec
 
(1.21x baseline)
Kyoto TreeDB1,230,000 ops/sec
 
(3.60x baseline)
SQLite3383,000 ops/sec
 
(1.00x baseline)
+

Random Reads

+ + + + + + + + + + + + + +
LevelDB149,000 ops/sec
 
(1.16x baseline)
Kyoto TreeDB175,000 ops/sec
 
(1.16x baseline)
SQLite3134,000 ops/sec
 
(1.00x baseline)
+ +

Performance of both LevelDB and TreeDB improves a small amount when +compression is disabled. Note however that under different workloads, +performance may very well be better with compression if it allows more +of the working set to fit in memory.

+ +

Note about Ext4 Filesystems

+

The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.

+ +

Acknowledgements

+

Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.

+ + diff --git a/doc/doc.css b/doc/doc.css new file mode 100644 index 000000000..700c564e4 --- /dev/null +++ b/doc/doc.css @@ -0,0 +1,89 @@ +body { + margin-left: 0.5in; + margin-right: 0.5in; + background: white; + color: black; +} + +h1 { + margin-left: -0.2in; + font-size: 14pt; +} +h2 { + margin-left: -0in; + font-size: 12pt; +} +h3 { + margin-left: -0in; +} +h4 { + margin-left: -0in; +} +hr { + margin-left: -0in; +} + +/* Definition lists: definition term bold */ +dt { + font-weight: bold; +} + +address { + text-align: center; +} +code,samp,var { + color: blue; +} +kbd { + color: #600000; +} +div.note p { + float: right; + width: 3in; + margin-right: 0%; + padding: 1px; + border: 2px solid #6060a0; + background-color: #fffff0; +} + +ul { + margin-top: -0em; + margin-bottom: -0em; +} + +ol { + margin-top: -0em; + margin-bottom: -0em; +} + +UL.nobullets { + list-style-type: none; + list-style-image: none; + margin-left: -1em; +} + +p { + margin: 1em 0 1em 0; + padding: 0 0 0 0; +} + +pre { + line-height: 1.3em; + padding: 0.4em 0 0.8em 0; + margin: 0 0 0 0; + border: 0 0 0 0; + color: blue; +} + +.datatable { + margin-left: auto; + margin-right: auto; + margin-top: 2em; + margin-bottom: 2em; + border: 1px solid; +} + +.datatable td,th { + padding: 0 0.5em 0 0.5em; + text-align: right; +} diff --git a/doc/impl.html b/doc/impl.html new file mode 100644 index 000000000..e870795d2 --- /dev/null +++ b/doc/impl.html @@ -0,0 +1,213 @@ + + + + +Leveldb file layout and compactions + + + + +

Files

+ +The implementation of leveldb is similar in spirit to the +representation of a single + +Bigtable tablet (section 5.3). +However the organization of the files that make up the representation +is somewhat different and is explained below. + +

+Each database is represented by a set of files stored in a directory. +There are several different types of files as documented below: +

+

Log files

+

+A log file (*.log) stores a sequence of recent updates. Each update +is appended to the current log file. When the log file reaches a +pre-determined size (approximately 4MB by default), it is converted +to a sorted table (see below) and a new log file is created for future +updates. +

+A copy of the current log file is kept in an in-memory structure (the +memtable). This copy is consulted on every read so that read +operations reflect all logged updates. +

+

Sorted tables

+

+A sorted table (*.sst) stores a sequence of entries sorted by key. +Each entry is either a value for the key, or a deletion marker for the +key. (Deletion markers are kept around to hide obsolete values +present in older sorted tables). +

+The set of sorted tables are organized into a sequence of levels. The +sorted table generated from a log file is placed in a special young +level (also called level-0). When the number of young files exceeds a +certain threshold (currently four), all of the young files are merged +together with all of the overlapping level-1 files to produce a +sequence of new level-1 files (we create a new level-1 file for every +2MB of data.) +

+Files in the young level may contain overlapping keys. However files +in other levels have distinct non-overlapping key ranges. Consider +level number L where L >= 1. When the combined size of files in +level-L exceeds (10^L) MB (i.e., 10MB for level-1, 100MB for level-2, +...), one file in level-L, and all of the overlapping files in +level-(L+1) are merged to form a set of new files for level-(L+1). +These merges have the effect of gradually migrating new updates from +the young level to the largest level using only bulk reads and writes +(i.e., minimizing expensive seeks). + +

Manifest

+

+A MANIFEST file lists the set of sorted tables that make up each +level, the corresponding key ranges, and other important metadata. +A new MANIFEST file (with a new number embedded in the file name) +is created whenever the database is reopened. The MANIFEST file is +formatted as a log, and changes made to the serving state (as files +are added or removed) are appended to this log. +

+

Current

+

+CURRENT is a simple text file that contains the name of the latest +MANIFEST file. +

+

Info logs

+

+Informational messages are printed to files named LOG and LOG.old. +

+

Others

+

+Other files used for miscellaneous purposes may also be present +(LOCK, *.dbtmp). + +

Level 0

+When the log file grows above a certain size (1MB by default): +
    +
  • Create a brand new memtable and log file and direct future updates here +
  • In the background: +
      +
    • Write the contents of the previous memtable to an sstable +
    • Discard the memtable +
    • Delete the old log file and the old memtable +
    • Add the new sstable to the young (level-0) level. +
    +
+ +

Compactions

+ +

+When the size of level L exceeds its limit, we compact it in a +background thread. The compaction picks a file from level L and all +overlapping files from the next level L+1. Note that if a level-L +file overlaps only part of a level-(L+1) file, the entire file at +level-(L+1) is used as an input to the compaction and will be +discarded after the compaction. Aside: because level-0 is special +(files in it may overlap each other), we treat compactions from +level-0 to level-1 specially: a level-0 compaction may pick more than +one level-0 file in case some of these files overlap each other. + +

+A compaction merges the contents of the picked files to produce a +sequence of level-(L+1) files. We switch to producing a new +level-(L+1) file after the current output file has reached the target +file size (2MB). We also switch to a new output file when the key +range of the current output file has grown enough to overlap more then +ten level-(L+2) files. This last rule ensures that a later compaction +of a level-(L+1) file will not pick up too much data from level-(L+2). + +

+The old files are discarded and the new files are added to the serving +state. + +

+Compactions for a particular level rotate through the key space. In +more detail, for each level L, we remember the ending key of the last +compaction at level L. The next compaction for level L will pick the +first file that starts after this key (wrapping around to the +beginning of the key space if there is no such file). + +

+Compactions drop overwritten values. They also drop deletion markers +if there are no higher numbered levels that contain a file whose range +overlaps the current key. + +

Timing

+ +Level-0 compactions will read up to four 1MB files from level-0, and +at worst all the level-1 files (10MB). I.e., we will read 14MB and +write 14MB. + +

+Other than the special level-0 compactions, we will pick one 2MB file +from level L. In the worst case, this will overlap ~ 12 files from +level L+1 (10 because level-(L+1) is ten times the size of level-L, +and another two at the boundaries since the file ranges at level-L +will usually not be aligned with the file ranges at level-L+1). The +compaction will therefore read 26MB and write 26MB. Assuming a disk +IO rate of 100MB/s (ballpark range for modern drives), the worst +compaction cost will be approximately 0.5 second. + +

+If we throttle the background writing to something small, say 10% of +the full 100MB/s speed, a compaction may take up to 5 seconds. If the +user is writing at 10MB/s, we might build up lots of level-0 files +(~50 to hold the 5*10MB). This may signficantly increase the cost of +reads due to the overhead of merging more files together on every +read. + +

+Solution 1: To reduce this problem, we might want to increase the log +switching threshold when the number of level-0 files is large. Though +the downside is that the larger this threshold, the more memory we will +need to hold the corresponding memtable. + +

+Solution 2: We might want to decrease write rate artificially when the +number of level-0 files goes up. + +

+Solution 3: We work on reducing the cost of very wide merges. +Perhaps most of the level-0 files will have their blocks sitting +uncompressed in the cache and we will only need to worry about the +O(N) complexity in the merging iterator. + +

Number of files

+ +Instead of always making 2MB files, we could make larger files for +larger levels to reduce the total file count, though at the expense of +more bursty compactions. Alternatively, we could shard the set of +files into multiple directories. + +

+An experiment on an ext3 filesystem on Feb 04, 2011 shows +the following timings to do 100K file opens in directories with +varying number of files: + + + + + +
Files in directoryMicroseconds to open a file
10009
1000010
10000016
+So maybe even the sharding is not necessary on modern filesystems? + +

Recovery

+ +
    +
  • Read CURRENT to find name of the latest committed MANIFEST +
  • Read the named MANIFEST file +
  • Clean up stale files +
  • We could open all sstables here, but it is probably better to be lazy... +
  • Convert log chunk to a new level-0 sstable +
  • Start directing new writes to a new log file with recovered sequence# +
+ +

Garbage collection of files

+ +DeleteObsoleteFiles() is called at the end of every +compaction and at the end of recovery. It finds the names of all +files in the database. It deletes all log files that are not the +current log file. It deletes all table files that are not referenced +from some level and are not the output of an active compaction. + + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 000000000..3ed0ed9d9 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,549 @@ + + + + +Leveldb + + + +

Leveldb

+
Jeff Dean, Sanjay Ghemawat
+

+The leveldb library provides a persistent key value store. Keys and +values are arbitrary byte arrays. The keys are ordered within the key +value store according to a user-specified comparator function. + +

+

Opening A Database

+

+A leveldb database has a name which corresponds to a file system +directory. All of the contents of database are stored in this +directory. The following example shows how to open a database, +creating it if necessary: +

+

+  #include <assert>
+  #include "leveldb/db.h"
+
+  leveldb::DB* db;
+  leveldb::Options options;
+  options.create_if_missing = true;
+  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
+  assert(status.ok());
+  ...
+
+If you want to raise an error if the database already exists, add +the following line before the leveldb::DB::Open call: +
+  options.error_if_exists = true;
+
+

Status

+

+You may have noticed the leveldb::Status type above. Values of this +type are returned by most functions in leveldb that may encounter an +error. You can check if such a result is ok, and also print an +associated error message: +

+

+   leveldb::Status s = ...;
+   if (!s.ok()) cerr << s.ToString() << endl;
+
+

Closing A Database

+

+When you are done with a database, just delete the database object. +Example: +

+

+  ... open the db as described above ...
+  ... do something with db ...
+  delete db;
+
+

Reads And Writes

+

+The database provides Put, Delete, and Get methods to +modify/query the database. For example, the following code +moves the value stored under key1 to key2. +

+  std::string value;
+  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
+  if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
+  if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
+
+ +

Atomic Updates

+

+Note that if the process dies after the Put of key2 but before the +delete of key1, the same value may be left stored under multiple keys. +Such problems can be avoided by using the WriteBatch class to +atomically apply a set of updates: +

+

+  #include "leveldb/write_batch.h"
+  ...
+  std::string value;
+  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
+  if (s.ok()) {
+    leveldb::WriteBatch batch;
+    batch.Delete(key1);
+    batch.Put(key2, value);
+    s = db->Write(leveldb::WriteOptions(), &batch);
+  }
+
+The WriteBatch holds a sequence of edits to be made to the database, +and these edits within the batch are applied in order. Note that we +called Delete before Put so that if key1 is identical to key2, +we do not end up erroneously dropping the value entirely. +

+Apart from its atomicity benefits, WriteBatch may also be used to +speed up bulk updates by placing lots of individual mutations into the +same batch. + +

Synchronous Writes

+By default, each write to leveldb is asynchronous: it +returns after pushing the write from the process into the operating +system. The transfer from operating system memory to the underlying +persistent storage happens asynchronously. The sync flag +can be turned on for a particular write to make the write operation +not return until the data being written has been pushed all the way to +persistent storage. (On Posix systems, this is implemented by calling +either fsync(...) or fdatasync(...) or +msync(..., MS_SYNC) before the write operation returns.) +
+  leveldb::WriteOptions write_options;
+  write_options.sync = true;
+  db->Put(write_options, ...);
+
+Asynchronous writes are often more than a thousand times as fast as +synchronous writes. The downside of asynchronous writes is that a +crash of the machine may cause the last few updates to be lost. Note +that a crash of just the writing process (i.e., not a reboot) will not +cause any loss since even when sync is false, an update +is pushed from the process memory into the operating system before it +is considered done. + +

+Asynchronous writes can often be used safely. For example, when +loading a large amount of data into the database you can handle lost +updates by restarting the bulk load after a crash. A hybrid scheme is +also possible where every Nth write is synchronous, and in the event +of a crash, the bulk load is restarted just after the last synchronous +write finished by the previous run. (The synchronous write can update +a marker that describes where to restart on a crash.) + +

+WriteBatch provides an alternative to asynchronous writes. +Multiple updates may be placed in the same WriteBatch and +applied together using a synchronous write (i.e., +write_options.sync is set to true). The extra cost of +the synchronous write will be amortized across all of the writes in +the batch. + +

+

Concurrency

+

+A database may only be opened by one process at a time. +The leveldb implementation acquires a lock from the +operating system to prevent misuse. Within a single process, the +same leveldb::DB object may be safely shared by multiple +concurrent threads. I.e., different threads may write into or fetch +iterators or call Get on the same database without any +external synchronization (the leveldb implementation will +automatically do the required synchronization). However other objects +(like Iterator and WriteBatch) may require external synchronization. +If two threads share such an object, they must protect access to it +using their own locking protocol. More details are available in +the public header files. +

+

Iteration

+

+The following example demonstrates how to print all key,value pairs +in a database. +

+

+  leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
+  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;
+  }
+  assert(it->status().ok());  // Check for any errors found during the scan
+  delete it;
+
+The following variation shows how to process just the keys in the +range [start,limit): +

+

+  for (it->Seek(start);
+       it->Valid() && it->key().ToString() < limit;
+       it->Next()) {
+    ...
+  }
+
+You can also process entries in reverse order. (Caveat: reverse +iteration may be somewhat slower than forward iteration.) +

+

+  for (it->SeekToLast(); it->Valid(); it->Prev()) {
+    ...
+  }
+
+

Snapshots

+

+Snapshots provide consistent read-only views over the entire state of +the key-value store. ReadOptions::snapshot may be non-NULL to indicate +that a read should operate on a particular version of the DB state. +If ReadOptions::snapshot is NULL, the read will operate on an +implicit snapshot of the current state. +

+Snapshots are created by the DB::GetSnapshot() method: +

+

+  leveldb::ReadOptions options;
+  options.snapshot = db->GetSnapshot();
+  ... apply some updates to db ...
+  leveldb::Iterator* iter = db->NewIterator(options);
+  ... read using iter to view the state when the snapshot was created ...
+  delete iter;
+  db->ReleaseSnapshot(options.snapshot);
+
+Note that when a snapshot is no longer needed, it should be released +using the DB::ReleaseSnapshot interface. This allows the +implementation to get rid of state that was being maintained just to +support reading as of that snapshot. +

Slice

+

+The return value of the it->key() and it->value() calls above +are instances of the leveldb::Slice type. Slice is a simple +structure that contains a length and a pointer to an external byte +array. Returning a Slice is a cheaper alternative to returning a +std::string since we do not need to copy potentially large keys and +values. In addition, leveldb methods do not return null-terminated +C-style strings since leveldb keys and values are allowed to +contain '\0' bytes. +

+C++ strings and null-terminated C-style strings can be easily converted +to a Slice: +

+

+   leveldb::Slice s1 = "hello";
+
+   std::string str("world");
+   leveldb::Slice s2 = str;
+
+A Slice can be easily converted back to a C++ string: +
+   std::string str = s1.ToString();
+   assert(str == std::string("hello"));
+
+Be careful when using Slices since it is up to the caller to ensure that +the external byte array into which the Slice points remains live while +the Slice is in use. For example, the following is buggy: +

+

+   leveldb::Slice slice;
+   if (...) {
+     std::string str = ...;
+     slice = str;
+   }
+   Use(slice);
+
+When the if statement goes out of scope, str will be destroyed and the +backing storage for slice will disappear. +

+

Comparators

+

+The preceding examples used the default ordering function for key, +which orders bytes lexicographically. You can however supply a custom +comparator when opening a database. For example, suppose each +database key consists of two numbers and we should sort by the first +number, breaking ties by the second number. First, define a proper +subclass of leveldb::Comparator that expresses these rules: +

+

+  class TwoPartComparator : public leveldb::Comparator {
+   public:
+    // Three-way comparison function:
+    //   if a < b: negative result
+    //   if a > b: positive result
+    //   else: zero result
+    int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
+      int a1, a2, b1, b2;
+      ParseKey(a, &a1, &a2);
+      ParseKey(b, &b1, &b2);
+      if (a1 < b1) return -1;
+      if (a1 > b1) return +1;
+      if (a2 < b2) return -1;
+      if (a2 > b2) return +1;
+      return 0;
+    }
+
+    // Ignore the following methods for now:
+    const char* Name() const { return "TwoPartComparator"; }
+    void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
+    void FindShortSuccessor(std::string*) const { }
+  };
+
+Now create a database using this custom comparator: +

+

+  TwoPartComparator cmp;
+  leveldb::DB* db;
+  leveldb::Options options;
+  options.create_if_missing = true;
+  options.comparator = &cmp;
+  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
+  ...
+
+

Backwards compatibility

+

+The result of the comparator's Name method is attached to the +database when it is created, and is checked on every subsequent +database open. If the name changes, the leveldb::DB::Open call will +fail. Therefore, change the name if and only if the new key format +and comparison function are incompatible with existing databases, and +it is ok to discard the contents of all existing databases. +

+You can however still gradually evolve your key format over time with +a little bit of pre-planning. For example, you could store a version +number at the end of each key (one byte should suffice for most uses). +When you wish to switch to a new key format (e.g., adding an optional +third part to the keys processed by TwoPartComparator), +(a) keep the same comparator name (b) increment the version number +for new keys (c) change the comparator function so it uses the +version numbers found in the keys to decide how to interpret them. +

+

Performance

+

+Performance can be tuned by changing the default values of the +types defined in include/leveldb/options.h. + +

+

Block size

+

+leveldb groups adjacent keys together into the same block and such a +block is the unit of transfer to and from persistent storage. The +default block size is approximately 4096 uncompressed bytes. +Applications that mostly do bulk scans over the contents of the +database may wish to increase this size. Applications that do a lot +of point reads of small values may wish to switch to a smaller block +size if performance measurements indicate an improvement. There isn't +much benefit in using blocks smaller than one kilobyte, or larger than +a few megabytes. Also note that compression will be more effective +with larger block sizes. +

+

Compression

+

+Each block is individually compressed before being written to +persistent storage. Compression is on by default since the default +compression method is very fast, and is automatically disabled for +uncompressible data. In rare cases, applications may want to disable +compression entirely, but should only do so if benchmarks show a +performance improvement: +

+

+  leveldb::Options options;
+  options.compression = leveldb::kNoCompression;
+  ... leveldb::DB::Open(options, name, ...) ....
+
+

Cache

+

+The contents of the database are stored in a set of files in the +filesystem and each file stores a sequence of compressed blocks. If +options.cache is non-NULL, it is used to cache frequently used +uncompressed block contents. +

+

+  #include "leveldb/cache.h"
+
+  leveldb::Options options;
+  options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
+  leveldb::DB* db;
+  leveldb::DB::Open(options, name, &db);
+  ... use the db ...
+  delete db
+  delete options.cache;
+
+Note that the cache holds uncompressed data, and therefore it should +be sized according to application level data sizes, without any +reduction from compression. (Caching of compressed blocks is left to +the operating system buffer cache, or any custom Env +implementation provided by the client.) +

+When performing a bulk read, the application may wish to disable +caching so that the data processed by the bulk read does not end up +displacing most of the cached contents. A per-iterator option can be +used to achieve this: +

+

+  leveldb::ReadOptions options;
+  options.fill_cache = false;
+  leveldb::Iterator* it = db->NewIterator(options);
+  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+    ...
+  }
+
+

Key Layout

+

+Note that the unit of disk transfer and caching is a block. Adjacent +keys (according to the database sort order) will usually be placed in +the same block. Therefore the application can improve its performance +by placing keys that are accessed together near each other and placing +infrequently used keys in a separate region of the key space. +

+For example, suppose we are implementing a simple file system on top +of leveldb. The types of entries we might wish to store are: +

+

+   filename -> permission-bits, length, list of file_block_ids
+   file_block_id -> data
+
+We might want to prefix filename keys with one letter (say '/') and the +file_block_id keys with a different letter (say '0') so that scans +over just the metadata do not force us to fetch and cache bulky file +contents. +

+

Filters

+

+Because of the way leveldb data is organized on disk, +a single Get() call may involve multiple reads from disk. +The optional FilterPolicy mechanism can be used to reduce +the number of disk reads substantially. +

+   leveldb::Options options;
+   options.filter_policy = NewBloomFilterPolicy(10);
+   leveldb::DB* db;
+   leveldb::DB::Open(options, "/tmp/testdb", &db);
+   ... use the database ...
+   delete db;
+   delete options.filter_policy;
+
+The preceding code associates a +Bloom filter +based filtering policy with the database. Bloom filter based +filtering relies on keeping some number of bits of data in memory per +key (in this case 10 bits per key since that is the argument we passed +to NewBloomFilterPolicy). This filter will reduce the number of unnecessary +disk reads needed for Get() calls by a factor of +approximately a 100. Increasing the bits per key will lead to a +larger reduction at the cost of more memory usage. We recommend that +applications whose working set does not fit in memory and that do a +lot of random reads set a filter policy. +

+If you are using a custom comparator, you should ensure that the filter +policy you are using is compatible with your comparator. For example, +consider a comparator that ignores trailing spaces when comparing keys. +NewBloomFilterPolicy must not be used with such a comparator. +Instead, the application should provide a custom filter policy that +also ignores trailing spaces. For example: +

+  class CustomFilterPolicy : public leveldb::FilterPolicy {
+   private:
+    FilterPolicy* builtin_policy_;
+   public:
+    CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) { }
+    ~CustomFilterPolicy() { delete builtin_policy_; }
+
+    const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
+
+    void CreateFilter(const Slice* keys, int n, std::string* dst) const {
+      // Use builtin bloom filter code after removing trailing spaces
+      std::vector<Slice> trimmed(n);
+      for (int i = 0; i < n; i++) {
+        trimmed[i] = RemoveTrailingSpaces(keys[i]);
+      }
+      return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
+    }
+
+    bool KeyMayMatch(const Slice& key, const Slice& filter) const {
+      // Use builtin bloom filter code after removing trailing spaces
+      return builtin_policy_->KeyMayMatch(RemoveTrailingSpaces(key), filter);
+    }
+  };
+
+

+Advanced applications may provide a filter policy that does not use +a bloom filter but uses some other mechanism for summarizing a set +of keys. See leveldb/filter_policy.h for detail. +

+

Checksums

+

+leveldb associates checksums with all data it stores in the file system. +There are two separate controls provided over how aggressively these +checksums are verified: +

+

    +
  • ReadOptions::verify_checksums may be set to true to force + checksum verification of all data that is read from the file system on + behalf of a particular read. By default, no such verification is + done. +

    +

  • Options::paranoid_checks may be set to true before opening a + database to make the database implementation raise an error as soon as + it detects an internal corruption. Depending on which portion of the + database has been corrupted, the error may be raised when the database + is opened, or later by another database operation. By default, + paranoid checking is off so that the database can be used even if + parts of its persistent storage have been corrupted. +

    + If a database is corrupted (perhaps it cannot be opened when + paranoid checking is turned on), the leveldb::RepairDB function + may be used to recover as much of the data as possible +

    +

+

Approximate Sizes

+

+The GetApproximateSizes method can used to get the approximate +number of bytes of file system space used by one or more key ranges. +

+

+   leveldb::Range ranges[2];
+   ranges[0] = leveldb::Range("a", "c");
+   ranges[1] = leveldb::Range("x", "z");
+   uint64_t sizes[2];
+   leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
+
+The preceding call will set sizes[0] to the approximate number of +bytes of file system space used by the key range [a..c) and +sizes[1] to the approximate number of bytes used by the key range +[x..z). +

+

Environment

+

+All file operations (and other operating system calls) issued by the +leveldb implementation are routed through a leveldb::Env object. +Sophisticated clients may wish to provide their own Env +implementation to get better control. For example, an application may +introduce artificial delays in the file IO paths to limit the impact +of leveldb on other activities in the system. +

+

+  class SlowEnv : public leveldb::Env {
+    .. implementation of the Env interface ...
+  };
+
+  SlowEnv env;
+  leveldb::Options options;
+  options.env = &env;
+  Status s = leveldb::DB::Open(options, ...);
+
+

Porting

+

+leveldb may be ported to a new platform by providing platform +specific implementations of the types/methods/functions exported by +leveldb/port/port.h. See leveldb/port/port_example.h for more +details. +

+In addition, the new platform may need a new default leveldb::Env +implementation. See leveldb/util/env_posix.h for an example. + +

Other Information

+ +

+Details about the leveldb implementation may be found in +the following documents: +

+ + + diff --git a/doc/log_format.txt b/doc/log_format.txt new file mode 100644 index 000000000..5228f624d --- /dev/null +++ b/doc/log_format.txt @@ -0,0 +1,75 @@ +The log file contents are a sequence of 32KB blocks. The only +exception is that the tail of the file may contain a partial block. + +Each block consists of a sequence of records: + block := record* trailer? + record := + checksum: uint32 // crc32c of type and data[] ; little-endian + length: uint16 // little-endian + type: uint8 // One of FULL, FIRST, MIDDLE, LAST + data: uint8[length] + +A record never starts within the last six bytes of a block (since it +won't fit). Any leftover bytes here form the trailer, which must +consist entirely of zero bytes and must be skipped by readers. + +Aside: if exactly seven bytes are left in the current block, and a new +non-zero length record is added, the writer must emit a FIRST record +(which contains zero bytes of user data) to fill up the trailing seven +bytes of the block and then emit all of the user data in subsequent +blocks. + +More types may be added in the future. Some Readers may skip record +types they do not understand, others may report that some data was +skipped. + +FULL == 1 +FIRST == 2 +MIDDLE == 3 +LAST == 4 + +The FULL record contains the contents of an entire user record. + +FIRST, MIDDLE, LAST are types used for user records that have been +split into multiple fragments (typically because of block boundaries). +FIRST is the type of the first fragment of a user record, LAST is the +type of the last fragment of a user record, and MID is the type of all +interior fragments of a user record. + +Example: consider a sequence of user records: + A: length 1000 + B: length 97270 + C: length 8000 +A will be stored as a FULL record in the first block. + +B will be split into three fragments: first fragment occupies the rest +of the first block, second fragment occupies the entirety of the +second block, and the third fragment occupies a prefix of the third +block. This will leave six bytes free in the third block, which will +be left empty as the trailer. + +C will be stored as a FULL record in the fourth block. + +=================== + +Some benefits over the recordio format: + +(1) We do not need any heuristics for resyncing - just go to next +block boundary and scan. If there is a corruption, skip to the next +block. As a side-benefit, we do not get confused when part of the +contents of one log file are embedded as a record inside another log +file. + +(2) Splitting at approximate boundaries (e.g., for mapreduce) is +simple: find the next block boundary and skip records until we +hit a FULL or FIRST record. + +(3) We do not need extra buffering for large records. + +Some downsides compared to recordio format: + +(1) No packing of tiny records. This could be fixed by adding a new +record type, so it is a shortcoming of the current implementation, +not necessarily the format. + +(2) No compression. Again, this could be fixed by adding new record types. diff --git a/doc/table_format.txt b/doc/table_format.txt new file mode 100644 index 000000000..ca8f9b446 --- /dev/null +++ b/doc/table_format.txt @@ -0,0 +1,104 @@ +File format +=========== + + + [data block 1] + [data block 2] + ... + [data block N] + [meta block 1] + ... + [meta block K] + [metaindex block] + [index block] + [Footer] (fixed size; starts at file_size - sizeof(Footer)) + + +The file contains internal pointers. Each such pointer is called +a BlockHandle and contains the following information: + offset: varint64 + size: varint64 +See https://developers.google.com/protocol-buffers/docs/encoding#varints +for an explanation of varint64 format. + +(1) The sequence of key/value pairs in the file are stored in sorted +order and partitioned into a sequence of data blocks. These blocks +come one after another at the beginning of the file. Each data block +is formatted according to the code in block_builder.cc, and then +optionally compressed. + +(2) After the data blocks we store a bunch of meta blocks. The +supported meta block types are described below. More meta block types +may be added in the future. Each meta block is again formatted using +block_builder.cc and then optionally compressed. + +(3) A "metaindex" block. It contains one entry for every other meta +block where the key is the name of the meta block and the value is a +BlockHandle pointing to that meta block. + +(4) An "index" block. This block contains one entry per data block, +where the key is a string >= last key in that data block and before +the first key in the successive data block. The value is the +BlockHandle for the data block. + +(6) At the very end of the file is a fixed length footer that contains +the BlockHandle of the metaindex and index blocks as well as a magic number. + metaindex_handle: char[p]; // Block handle for metaindex + index_handle: char[q]; // Block handle for index + padding: char[40-p-q]; // zeroed bytes to make fixed length + // (40==2*BlockHandle::kMaxEncodedLength) + magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) + +"filter" Meta Block +------------------- + +If a "FilterPolicy" was specified when the database was opened, a +filter block is stored in each table. The "metaindex" block contains +an entry that maps from "filter." to the BlockHandle for the filter +block where "" is the string returned by the filter policy's +"Name()" method. + +The filter block stores a sequence of filters, where filter i contains +the output of FilterPolicy::CreateFilter() on all keys that are stored +in a block whose file offset falls within the range + + [ i*base ... (i+1)*base-1 ] + +Currently, "base" is 2KB. So for example, if blocks X and Y start in +the range [ 0KB .. 2KB-1 ], all of the keys in X and Y will be +converted to a filter by calling FilterPolicy::CreateFilter(), and the +resulting filter will be stored as the first filter in the filter +block. + +The filter block is formatted as follows: + + [filter 0] + [filter 1] + [filter 2] + ... + [filter N-1] + + [offset of filter 0] : 4 bytes + [offset of filter 1] : 4 bytes + [offset of filter 2] : 4 bytes + ... + [offset of filter N-1] : 4 bytes + + [offset of beginning of offset array] : 4 bytes + lg(base) : 1 byte + +The offset array at the end of the filter block allows efficient +mapping from a data block offset to the corresponding filter. + +"stats" Meta Block +------------------ + +This meta block contains a bunch of stats. The key is the name +of the statistic. The value contains the statistic. +TODO(postrelease): record following stats. + data size + index size + key size (uncompressed) + value size (uncompressed) + number of entries + number of data blocks diff --git a/helpers/memenv/memenv.cc b/helpers/memenv/memenv.cc new file mode 100644 index 000000000..5879de121 --- /dev/null +++ b/helpers/memenv/memenv.cc @@ -0,0 +1,384 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "helpers/memenv/memenv.h" + +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "port/port.h" +#include "util/mutexlock.h" +#include +#include +#include +#include + +namespace leveldb { + +namespace { + +class FileState { + public: + // FileStates are reference counted. The initial reference count is zero + // and the caller must call Ref() at least once. + FileState() : refs_(0), size_(0) {} + + // Increase the reference count. + void Ref() { + MutexLock lock(&refs_mutex_); + ++refs_; + } + + // Decrease the reference count. Delete if this is the last reference. + void Unref() { + bool do_delete = false; + + { + MutexLock lock(&refs_mutex_); + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + do_delete = true; + } + } + + if (do_delete) { + delete this; + } + } + + uint64_t Size() const { return size_; } + + Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { + if (offset > size_) { + return Status::IOError("Offset greater than file size."); + } + const uint64_t available = size_ - offset; + if (n > available) { + n = available; + } + if (n == 0) { + *result = Slice(); + return Status::OK(); + } + + size_t block = offset / kBlockSize; + size_t block_offset = offset % kBlockSize; + + if (n <= kBlockSize - block_offset) { + // The requested bytes are all in the first block. + *result = Slice(blocks_[block] + block_offset, n); + return Status::OK(); + } + + size_t bytes_to_copy = n; + char* dst = scratch; + + while (bytes_to_copy > 0) { + size_t avail = kBlockSize - block_offset; + if (avail > bytes_to_copy) { + avail = bytes_to_copy; + } + memcpy(dst, blocks_[block] + block_offset, avail); + + bytes_to_copy -= avail; + dst += avail; + block++; + block_offset = 0; + } + + *result = Slice(scratch, n); + return Status::OK(); + } + + Status Append(const Slice& data) { + const char* src = data.data(); + size_t src_len = data.size(); + + while (src_len > 0) { + size_t avail; + size_t offset = size_ % kBlockSize; + + if (offset != 0) { + // There is some room in the last block. + avail = kBlockSize - offset; + } else { + // No room in the last block; push new one. + blocks_.push_back(new char[kBlockSize]); + avail = kBlockSize; + } + + if (avail > src_len) { + avail = src_len; + } + memcpy(blocks_.back() + offset, src, avail); + src_len -= avail; + src += avail; + size_ += avail; + } + + return Status::OK(); + } + + private: + // Private since only Unref() should be used to delete it. + ~FileState() { + for (std::vector::iterator i = blocks_.begin(); i != blocks_.end(); + ++i) { + delete [] *i; + } + } + + // No copying allowed. + FileState(const FileState&); + void operator=(const FileState&); + + port::Mutex refs_mutex_; + int refs_; // Protected by refs_mutex_; + + // The following fields are not protected by any mutex. They are only mutable + // while the file is being written, and concurrent access is not allowed + // to writable files. + std::vector blocks_; + uint64_t size_; + + enum { kBlockSize = 8 * 1024 }; +}; + +class SequentialFileImpl : public SequentialFile { + public: + explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) { + file_->Ref(); + } + + ~SequentialFileImpl() { + file_->Unref(); + } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s = file_->Read(pos_, n, result, scratch); + if (s.ok()) { + pos_ += result->size(); + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (pos_ > file_->Size()) { + return Status::IOError("pos_ > file_->Size()"); + } + const size_t available = file_->Size() - pos_; + if (n > available) { + n = available; + } + pos_ += n; + return Status::OK(); + } + + private: + FileState* file_; + size_t pos_; +}; + +class RandomAccessFileImpl : public RandomAccessFile { + public: + explicit RandomAccessFileImpl(FileState* file) : file_(file) { + file_->Ref(); + } + + ~RandomAccessFileImpl() { + file_->Unref(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + return file_->Read(offset, n, result, scratch); + } + + private: + FileState* file_; +}; + +class WritableFileImpl : public WritableFile { + public: + WritableFileImpl(FileState* file) : file_(file) { + file_->Ref(); + } + + ~WritableFileImpl() { + file_->Unref(); + } + + virtual Status Append(const Slice& data) { + return file_->Append(data); + } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + private: + FileState* file_; +}; + +class NoOpLogger : public Logger { + public: + virtual void Logv(const char* format, va_list ap) { } +}; + +class InMemoryEnv : public EnvWrapper { + public: + explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { } + + virtual ~InMemoryEnv() { + for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ + i->second->Unref(); + } + } + + // Partial implementation of the Env interface. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + *result = NULL; + return Status::IOError(fname, "File not found"); + } + + *result = new SequentialFileImpl(file_map_[fname]); + return Status::OK(); + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + *result = NULL; + return Status::IOError(fname, "File not found"); + } + + *result = new RandomAccessFileImpl(file_map_[fname]); + return Status::OK(); + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) != file_map_.end()) { + DeleteFileInternal(fname); + } + + FileState* file = new FileState(); + file->Ref(); + file_map_[fname] = file; + + *result = new WritableFileImpl(file); + return Status::OK(); + } + + virtual bool FileExists(const std::string& fname) { + MutexLock lock(&mutex_); + return file_map_.find(fname) != file_map_.end(); + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + MutexLock lock(&mutex_); + result->clear(); + + for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ + const std::string& filename = i->first; + + if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' && + Slice(filename).starts_with(Slice(dir))) { + result->push_back(filename.substr(dir.size() + 1)); + } + } + + return Status::OK(); + } + + void DeleteFileInternal(const std::string& fname) { + if (file_map_.find(fname) == file_map_.end()) { + return; + } + + file_map_[fname]->Unref(); + file_map_.erase(fname); + } + + virtual Status DeleteFile(const std::string& fname) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + return Status::IOError(fname, "File not found"); + } + + DeleteFileInternal(fname); + return Status::OK(); + } + + virtual Status CreateDir(const std::string& dirname) { + return Status::OK(); + } + + virtual Status DeleteDir(const std::string& dirname) { + return Status::OK(); + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + return Status::IOError(fname, "File not found"); + } + + *file_size = file_map_[fname]->Size(); + return Status::OK(); + } + + virtual Status RenameFile(const std::string& src, + const std::string& target) { + MutexLock lock(&mutex_); + if (file_map_.find(src) == file_map_.end()) { + return Status::IOError(src, "File not found"); + } + + DeleteFileInternal(target); + file_map_[target] = file_map_[src]; + file_map_.erase(src); + return Status::OK(); + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = new FileLock; + return Status::OK(); + } + + virtual Status UnlockFile(FileLock* lock) { + delete lock; + return Status::OK(); + } + + virtual Status GetTestDirectory(std::string* path) { + *path = "/test"; + return Status::OK(); + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + *result = new NoOpLogger; + return Status::OK(); + } + + private: + // Map from filenames to FileState objects, representing a simple file system. + typedef std::map FileSystem; + port::Mutex mutex_; + FileSystem file_map_; // Protected by mutex_. +}; + +} // namespace + +Env* NewMemEnv(Env* base_env) { + return new InMemoryEnv(base_env); +} + +} // namespace leveldb diff --git a/helpers/memenv/memenv.h b/helpers/memenv/memenv.h new file mode 100644 index 000000000..03b88de76 --- /dev/null +++ b/helpers/memenv/memenv.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ +#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ + +namespace leveldb { + +class Env; + +// Returns a new environment that stores its data in memory and delegates +// all non-file-storage tasks to base_env. The caller must delete the result +// when it is no longer needed. +// *base_env must remain live while the result is in use. +Env* NewMemEnv(Env* base_env); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ diff --git a/helpers/memenv/memenv_test.cc b/helpers/memenv/memenv_test.cc new file mode 100644 index 000000000..a44310fed --- /dev/null +++ b/helpers/memenv/memenv_test.cc @@ -0,0 +1,232 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "helpers/memenv/memenv.h" + +#include "db/db_impl.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "util/testharness.h" +#include +#include + +namespace leveldb { + +class MemEnvTest { + public: + Env* env_; + + MemEnvTest() + : env_(NewMemEnv(Env::Default())) { + } + ~MemEnvTest() { + delete env_; + } +}; + +TEST(MemEnvTest, Basics) { + uint64_t file_size; + WritableFile* writable_file; + std::vector children; + + ASSERT_OK(env_->CreateDir("/dir")); + + // Check that the directory is empty. + ASSERT_TRUE(!env_->FileExists("/dir/non_existent")); + ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok()); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(0, children.size()); + + // Create a file. + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + delete writable_file; + + // Check that the file exists. + ASSERT_TRUE(env_->FileExists("/dir/f")); + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(0, file_size); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(1, children.size()); + ASSERT_EQ("f", children[0]); + + // Write to the file. + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("abc")); + delete writable_file; + + // Check for expected size. + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(3, file_size); + + // Check that renaming works. + ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); + ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g")); + ASSERT_TRUE(!env_->FileExists("/dir/f")); + ASSERT_TRUE(env_->FileExists("/dir/g")); + ASSERT_OK(env_->GetFileSize("/dir/g", &file_size)); + ASSERT_EQ(3, file_size); + + // Check that opening non-existent file fails. + SequentialFile* seq_file; + RandomAccessFile* rand_file; + ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok()); + ASSERT_TRUE(!seq_file); + ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok()); + ASSERT_TRUE(!rand_file); + + // Check that deleting works. + ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok()); + ASSERT_OK(env_->DeleteFile("/dir/g")); + ASSERT_TRUE(!env_->FileExists("/dir/g")); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(0, children.size()); + ASSERT_OK(env_->DeleteDir("/dir")); +} + +TEST(MemEnvTest, ReadWrite) { + WritableFile* writable_file; + SequentialFile* seq_file; + RandomAccessFile* rand_file; + Slice result; + char scratch[100]; + + ASSERT_OK(env_->CreateDir("/dir")); + + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("hello ")); + ASSERT_OK(writable_file->Append("world")); + delete writable_file; + + // Read sequentially. + ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); + ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello". + ASSERT_EQ(0, result.compare("hello")); + ASSERT_OK(seq_file->Skip(1)); + ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world". + ASSERT_EQ(0, result.compare("world")); + ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF. + ASSERT_EQ(0, result.size()); + ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file. + ASSERT_OK(seq_file->Read(1000, &result, scratch)); + ASSERT_EQ(0, result.size()); + delete seq_file; + + // Random reads. + ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file)); + ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world". + ASSERT_EQ(0, result.compare("world")); + ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello". + ASSERT_EQ(0, result.compare("hello")); + ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d". + ASSERT_EQ(0, result.compare("d")); + + // Too high offset. + ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok()); + delete rand_file; +} + +TEST(MemEnvTest, Locks) { + FileLock* lock; + + // These are no-ops, but we test they return success. + ASSERT_OK(env_->LockFile("some file", &lock)); + ASSERT_OK(env_->UnlockFile(lock)); +} + +TEST(MemEnvTest, Misc) { + std::string test_dir; + ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_TRUE(!test_dir.empty()); + + WritableFile* writable_file; + ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file)); + + // These are no-ops, but we test they return success. + ASSERT_OK(writable_file->Sync()); + ASSERT_OK(writable_file->Flush()); + ASSERT_OK(writable_file->Close()); + delete writable_file; +} + +TEST(MemEnvTest, LargeWrite) { + const size_t kWriteSize = 300 * 1024; + char* scratch = new char[kWriteSize * 2]; + + std::string write_data; + for (size_t i = 0; i < kWriteSize; ++i) { + write_data.append(1, static_cast(i)); + } + + WritableFile* writable_file; + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("foo")); + ASSERT_OK(writable_file->Append(write_data)); + delete writable_file; + + SequentialFile* seq_file; + Slice result; + ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); + ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo". + ASSERT_EQ(0, result.compare("foo")); + + size_t read = 0; + std::string read_data; + while (read < kWriteSize) { + ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch)); + read_data.append(result.data(), result.size()); + read += result.size(); + } + ASSERT_TRUE(write_data == read_data); + delete seq_file; + delete [] scratch; +} + +TEST(MemEnvTest, DBTest) { + Options options; + options.create_if_missing = true; + options.env = env_; + DB* db; + + const Slice keys[] = {Slice("aaa"), Slice("bbb"), Slice("ccc")}; + const Slice vals[] = {Slice("foo"), Slice("bar"), Slice("baz")}; + + ASSERT_OK(DB::Open(options, "/dir/db", &db)); + for (size_t i = 0; i < 3; ++i) { + ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i])); + } + + for (size_t i = 0; i < 3; ++i) { + std::string res; + ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); + ASSERT_TRUE(res == vals[i]); + } + + Iterator* iterator = db->NewIterator(ReadOptions()); + iterator->SeekToFirst(); + for (size_t i = 0; i < 3; ++i) { + ASSERT_TRUE(iterator->Valid()); + ASSERT_TRUE(keys[i] == iterator->key()); + ASSERT_TRUE(vals[i] == iterator->value()); + iterator->Next(); + } + ASSERT_TRUE(!iterator->Valid()); + delete iterator; + + DBImpl* dbi = reinterpret_cast(db); + ASSERT_OK(dbi->TEST_CompactMemTable()); + + for (size_t i = 0; i < 3; ++i) { + std::string res; + ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); + ASSERT_TRUE(res == vals[i]); + } + + delete db; +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/include/leveldb/c.h b/include/leveldb/c.h new file mode 100644 index 000000000..1fa58866c --- /dev/null +++ b/include/leveldb/c.h @@ -0,0 +1,291 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. + + C bindings for leveldb. May be useful as a stable ABI that can be + used by programs that keep leveldb in a shared library, or for + a JNI api. + + Does not support: + . getters for the option types + . custom comparators that implement key shortening + . capturing post-write-snapshot + . custom iter, db, env, cache implementations using just the C bindings + + Some conventions: + + (1) We expose just opaque struct pointers and functions to clients. + This allows us to change internal representations without having to + recompile clients. + + (2) For simplicity, there is no equivalent to the Slice type. Instead, + the caller has to pass the pointer and length as separate + arguments. + + (3) Errors are represented by a null-terminated c string. NULL + means no error. All operations that can raise an error are passed + a "char** errptr" as the last argument. One of the following must + be true on entry: + *errptr == NULL + *errptr points to a malloc()ed null-terminated error message + (On Windows, *errptr must have been malloc()-ed by this library.) + On success, a leveldb routine leaves *errptr unchanged. + On failure, leveldb frees the old value of *errptr and + set *errptr to a malloc()ed error message. + + (4) Bools have the type unsigned char (0 == false; rest == true) + + (5) All of the pointer arguments must be non-NULL. +*/ + +#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ +#define STORAGE_LEVELDB_INCLUDE_C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* Exported types */ + +typedef struct leveldb_t leveldb_t; +typedef struct leveldb_cache_t leveldb_cache_t; +typedef struct leveldb_comparator_t leveldb_comparator_t; +typedef struct leveldb_env_t leveldb_env_t; +typedef struct leveldb_filelock_t leveldb_filelock_t; +typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; +typedef struct leveldb_iterator_t leveldb_iterator_t; +typedef struct leveldb_logger_t leveldb_logger_t; +typedef struct leveldb_options_t leveldb_options_t; +typedef struct leveldb_randomfile_t leveldb_randomfile_t; +typedef struct leveldb_readoptions_t leveldb_readoptions_t; +typedef struct leveldb_seqfile_t leveldb_seqfile_t; +typedef struct leveldb_snapshot_t leveldb_snapshot_t; +typedef struct leveldb_writablefile_t leveldb_writablefile_t; +typedef struct leveldb_writebatch_t leveldb_writebatch_t; +typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; + +/* DB operations */ + +extern leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_close(leveldb_t* db); + +extern void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr); + +extern void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr); + +extern void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr); + +/* Returns NULL if not found. A malloc()ed array otherwise. + Stores the length of the array in *vallen. */ +extern char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr); + +extern leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options); + +extern const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db); + +extern void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot); + +/* Returns NULL if property name is unknown. + Else returns a pointer to a malloc()-ed null-terminated value. */ +extern char* leveldb_property_value( + leveldb_t* db, + const char* propname); + +extern void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes); + +extern void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len); + +/* Management operations */ + +extern void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +/* Iterator */ + +extern void leveldb_iter_destroy(leveldb_iterator_t*); +extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*); +extern void leveldb_iter_seek_to_first(leveldb_iterator_t*); +extern void leveldb_iter_seek_to_last(leveldb_iterator_t*); +extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen); +extern void leveldb_iter_next(leveldb_iterator_t*); +extern void leveldb_iter_prev(leveldb_iterator_t*); +extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen); +extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen); +extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr); + +/* Write batch */ + +extern leveldb_writebatch_t* leveldb_writebatch_create(); +extern void leveldb_writebatch_destroy(leveldb_writebatch_t*); +extern void leveldb_writebatch_clear(leveldb_writebatch_t*); +extern void leveldb_writebatch_put( + leveldb_writebatch_t*, + const char* key, size_t klen, + const char* val, size_t vlen); +extern void leveldb_writebatch_delete( + leveldb_writebatch_t*, + const char* key, size_t klen); +extern void leveldb_writebatch_iterate( + leveldb_writebatch_t*, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)); + +/* Options */ + +extern leveldb_options_t* leveldb_options_create(); +extern void leveldb_options_destroy(leveldb_options_t*); +extern void leveldb_options_set_comparator( + leveldb_options_t*, + leveldb_comparator_t*); +extern void leveldb_options_set_filter_policy( + leveldb_options_t*, + leveldb_filterpolicy_t*); +extern void leveldb_options_set_create_if_missing( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_error_if_exists( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_paranoid_checks( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); +extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*); +extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_max_open_files(leveldb_options_t*, int); +extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*); +extern void leveldb_options_set_block_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int); + +enum { + leveldb_no_compression = 0, + leveldb_snappy_compression = 1 +}; +extern void leveldb_options_set_compression(leveldb_options_t*, int); + +/* Comparator */ + +extern leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)); +extern void leveldb_comparator_destroy(leveldb_comparator_t*); + +/* Filter policy */ + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)); +extern void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( + int bits_per_key); + +/* Read options */ + +extern leveldb_readoptions_t* leveldb_readoptions_create(); +extern void leveldb_readoptions_destroy(leveldb_readoptions_t*); +extern void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t*, + unsigned char); +extern void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t*, unsigned char); +extern void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t*, + const leveldb_snapshot_t*); + +/* Write options */ + +extern leveldb_writeoptions_t* leveldb_writeoptions_create(); +extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); +extern void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t*, unsigned char); + +/* Cache */ + +extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); +extern void leveldb_cache_destroy(leveldb_cache_t* cache); + +/* Env */ + +extern leveldb_env_t* leveldb_create_default_env(); +extern void leveldb_env_destroy(leveldb_env_t*); + +/* Utility */ + +/* Calls free(ptr). + REQUIRES: ptr was malloc()-ed and returned by one of the routines + in this file. Note that in certain cases (typically on Windows), you + may need to call this routine instead of free(ptr) to dispose of + malloc()-ed memory returned by this library. */ +extern void leveldb_free(void* ptr); + +/* Return the major version number for this release. */ +extern int leveldb_major_version(); + +/* Return the minor version number for this release. */ +extern int leveldb_minor_version(); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/include/leveldb/cache.h b/include/leveldb/cache.h new file mode 100644 index 000000000..5e3b47637 --- /dev/null +++ b/include/leveldb/cache.h @@ -0,0 +1,99 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Cache is an interface that maps keys to values. It has internal +// synchronization and may be safely accessed concurrently from +// multiple threads. It may automatically evict entries to make room +// for new entries. Values have a specified charge against the cache +// capacity. For example, a cache where the values are variable +// length strings, may use the length of the string as the charge for +// the string. +// +// A builtin cache implementation with a least-recently-used eviction +// policy is provided. Clients may use their own implementations if +// they want something more sophisticated (like scan-resistance, a +// custom eviction policy, variable cache sizing, etc.) + +#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ +#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Cache; + +// Create a new cache with a fixed size capacity. This implementation +// of Cache uses a least-recently-used eviction policy. +extern Cache* NewLRUCache(size_t capacity); + +class Cache { + public: + Cache() { } + + // Destroys all existing entries by calling the "deleter" + // function that was passed to the constructor. + virtual ~Cache(); + + // Opaque handle to an entry stored in the cache. + struct Handle { }; + + // Insert a mapping from key->value into the cache and assign it + // the specified charge against the total cache capacity. + // + // Returns a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + // + // When the inserted entry is no longer needed, the key and + // value will be passed to "deleter". + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) = 0; + + // If the cache has no mapping for "key", returns NULL. + // + // Else return a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + virtual Handle* Lookup(const Slice& key) = 0; + + // Release a mapping returned by a previous Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void Release(Handle* handle) = 0; + + // Return the value encapsulated in a handle returned by a + // successful Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void* Value(Handle* handle) = 0; + + // If the cache contains entry for key, erase it. Note that the + // underlying entry will be kept around until all existing handles + // to it have been released. + virtual void Erase(const Slice& key) = 0; + + // Return a new numeric id. May be used by multiple clients who are + // sharing the same cache to partition the key space. Typically the + // client will allocate a new id at startup and prepend the id to + // its cache keys. + virtual uint64_t NewId() = 0; + + private: + void LRU_Remove(Handle* e); + void LRU_Append(Handle* e); + void Unref(Handle* e); + + struct Rep; + Rep* rep_; + + // No copying allowed + Cache(const Cache&); + void operator=(const Cache&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CACHE_H_ diff --git a/include/leveldb/comparator.h b/include/leveldb/comparator.h new file mode 100644 index 000000000..556b984c7 --- /dev/null +++ b/include/leveldb/comparator.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ + +#include + +namespace leveldb { + +class Slice; + +// A Comparator object provides a total order across slices that are +// used as keys in an sstable or a database. A Comparator implementation +// must be thread-safe since leveldb may invoke its methods concurrently +// from multiple threads. +class Comparator { + public: + virtual ~Comparator(); + + // Three-way comparison. Returns value: + // < 0 iff "a" < "b", + // == 0 iff "a" == "b", + // > 0 iff "a" > "b" + virtual int Compare(const Slice& a, const Slice& b) const = 0; + + // The name of the comparator. Used to check for comparator + // mismatches (i.e., a DB created with one comparator is + // accessed using a different comparator. + // + // The client of this package should switch to a new name whenever + // the comparator implementation changes in a way that will cause + // the relative ordering of any two keys to change. + // + // Names starting with "leveldb." are reserved and should not be used + // by any clients of this package. + virtual const char* Name() const = 0; + + // Advanced functions: these are used to reduce the space requirements + // for internal data structures like index blocks. + + // If *start < limit, changes *start to a short string in [start,limit). + // Simple comparator implementations may return with *start unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const = 0; + + // Changes *key to a short string >= *key. + // Simple comparator implementations may return with *key unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortSuccessor(std::string* key) const = 0; +}; + +// Return a builtin comparator that uses lexicographic byte-wise +// ordering. The result remains the property of this module and +// must not be deleted. +extern const Comparator* BytewiseComparator(); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/include/leveldb/db.h b/include/leveldb/db.h new file mode 100644 index 000000000..29d367447 --- /dev/null +++ b/include/leveldb/db.h @@ -0,0 +1,161 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_ +#define STORAGE_LEVELDB_INCLUDE_DB_H_ + +#include +#include +#include "leveldb/iterator.h" +#include "leveldb/options.h" + +namespace leveldb { + +// Update Makefile if you change these +static const int kMajorVersion = 1; +static const int kMinorVersion = 9; + +struct Options; +struct ReadOptions; +struct WriteOptions; +class WriteBatch; + +// Abstract handle to particular state of a DB. +// A Snapshot is an immutable object and can therefore be safely +// accessed from multiple threads without any external synchronization. +class Snapshot { + protected: + virtual ~Snapshot(); +}; + +// A range of keys +struct Range { + Slice start; // Included in the range + Slice limit; // Not included in the range + + Range() { } + Range(const Slice& s, const Slice& l) : start(s), limit(l) { } +}; + +// A DB is a persistent ordered map from keys to values. +// A DB is safe for concurrent access from multiple threads without +// any external synchronization. +class DB { + public: + // Open the database with the specified "name". + // Stores a pointer to a heap-allocated database in *dbptr and returns + // OK on success. + // Stores NULL in *dbptr and returns a non-OK status on error. + // Caller should delete *dbptr when it is no longer needed. + static Status Open(const Options& options, + const std::string& name, + DB** dbptr); + + DB() { } + virtual ~DB(); + + // Set the database entry for "key" to "value". Returns OK on success, + // and a non-OK status on error. + // Note: consider setting options.sync = true. + virtual Status Put(const WriteOptions& options, + const Slice& key, + const Slice& value) = 0; + + // Remove the database entry (if any) for "key". Returns OK on + // success, and a non-OK status on error. It is not an error if "key" + // did not exist in the database. + // Note: consider setting options.sync = true. + virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; + + // Apply the specified updates to the database. + // Returns OK on success, non-OK on failure. + // Note: consider setting options.sync = true. + virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; + + // If the database contains an entry for "key" store the + // corresponding value in *value and return OK. + // + // If there is no entry for "key" leave *value unchanged and return + // a status for which Status::IsNotFound() returns true. + // + // May return some other Status on an error. + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) = 0; + + // Return a heap-allocated iterator over the contents of the database. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + // + // Caller should delete the iterator when it is no longer needed. + // The returned iterator should be deleted before this db is deleted. + virtual Iterator* NewIterator(const ReadOptions& options) = 0; + + // Return a handle to the current DB state. Iterators created with + // this handle will all observe a stable snapshot of the current DB + // state. The caller must call ReleaseSnapshot(result) when the + // snapshot is no longer needed. + virtual const Snapshot* GetSnapshot() = 0; + + // Release a previously acquired snapshot. The caller must not + // use "snapshot" after this call. + virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; + + // DB implementations can export properties about their state + // via this method. If "property" is a valid property understood by this + // DB implementation, fills "*value" with its current value and returns + // true. Otherwise returns false. + // + // + // Valid property names include: + // + // "leveldb.num-files-at-level" - return the number of files at level , + // where is an ASCII representation of a level number (e.g. "0"). + // "leveldb.stats" - returns a multi-line string that describes statistics + // about the internal operation of the DB. + // "leveldb.sstables" - returns a multi-line string that describes all + // of the sstables that make up the db contents. + virtual bool GetProperty(const Slice& property, std::string* value) = 0; + + // For each i in [0,n-1], store in "sizes[i]", the approximate + // file system space used by keys in "[range[i].start .. range[i].limit)". + // + // Note that the returned sizes measure file system space usage, so + // if the user data compresses by a factor of ten, the returned + // sizes will be one-tenth the size of the corresponding user data size. + // + // The results may not include the sizes of recently written data. + virtual void GetApproximateSizes(const Range* range, int n, + uint64_t* sizes) = 0; + + // Compact the underlying storage for the key range [*begin,*end]. + // In particular, deleted and overwritten versions are discarded, + // and the data is rearranged to reduce the cost of operations + // needed to access the data. This operation should typically only + // be invoked by users who understand the underlying implementation. + // + // begin==NULL is treated as a key before all keys in the database. + // end==NULL is treated as a key after all keys in the database. + // Therefore the following call will compact the entire database: + // db->CompactRange(NULL, NULL); + virtual void CompactRange(const Slice* begin, const Slice* end) = 0; + + private: + // No copying allowed + DB(const DB&); + void operator=(const DB&); +}; + +// Destroy the contents of the specified database. +// Be very careful using this method. +Status DestroyDB(const std::string& name, const Options& options); + +// If a DB cannot be opened, you may attempt to call this method to +// resurrect as much of the contents of the database as possible. +// Some data may be lost, so be careful when calling this function +// on a database that contains important information. +Status RepairDB(const std::string& dbname, const Options& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/include/leveldb/env.h b/include/leveldb/env.h new file mode 100644 index 000000000..fa32289f5 --- /dev/null +++ b/include/leveldb/env.h @@ -0,0 +1,333 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An Env is an interface used by the leveldb implementation to access +// operating system functionality like the filesystem etc. Callers +// may wish to provide a custom Env object when opening a database to +// get fine gain control; e.g., to rate limit file system operations. +// +// All Env implementations are safe for concurrent access from +// multiple threads without any external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ +#define STORAGE_LEVELDB_INCLUDE_ENV_H_ + +#include +#include +#include +#include +#include "leveldb/status.h" + +namespace leveldb { + +class FileLock; +class Logger; +class RandomAccessFile; +class SequentialFile; +class Slice; +class WritableFile; + +class Env { + public: + Env() { } + virtual ~Env(); + + // Return a default environment suitable for the current operating + // system. Sophisticated users may wish to provide their own Env + // implementation instead of relying on this default environment. + // + // The result of Default() belongs to leveldb and must never be deleted. + static Env* Default(); + + // Create a brand new sequentially-readable file with the specified name. + // On success, stores a pointer to the new file in *result and returns OK. + // On failure stores NULL in *result and returns non-OK. If the file does + // not exist, returns a non-OK status. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) = 0; + + // Create a brand new random access read-only file with the + // specified name. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. If the file does not exist, returns a non-OK + // status. + // + // The returned file may be concurrently accessed by multiple threads. + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) = 0; + + // Create an object that writes to a new file with the specified + // name. Deletes any existing file with the same name and creates a + // new file. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) = 0; + + // Returns true iff the named file exists. + virtual bool FileExists(const std::string& fname) = 0; + + // Store in *result the names of the children of the specified directory. + // The names are relative to "dir". + // Original contents of *results are dropped. + virtual Status GetChildren(const std::string& dir, + std::vector* result) = 0; + + // Delete the named file. + virtual Status DeleteFile(const std::string& fname) = 0; + + // Create the specified directory. + virtual Status CreateDir(const std::string& dirname) = 0; + + // Delete the specified directory. + virtual Status DeleteDir(const std::string& dirname) = 0; + + // Store the size of fname in *file_size. + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; + + // Rename file src to target. + virtual Status RenameFile(const std::string& src, + const std::string& target) = 0; + + // Lock the specified file. Used to prevent concurrent access to + // the same db by multiple processes. On failure, stores NULL in + // *lock and returns non-OK. + // + // On success, stores a pointer to the object that represents the + // acquired lock in *lock and returns OK. The caller should call + // UnlockFile(*lock) to release the lock. If the process exits, + // the lock will be automatically released. + // + // If somebody else already holds the lock, finishes immediately + // with a failure. I.e., this call does not wait for existing locks + // to go away. + // + // May create the named file if it does not already exist. + virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; + + // Release the lock acquired by a previous successful call to LockFile. + // REQUIRES: lock was returned by a successful LockFile() call + // REQUIRES: lock has not already been unlocked. + virtual Status UnlockFile(FileLock* lock) = 0; + + // Arrange to run "(*function)(arg)" once in a background thread. + // + // "function" may run in an unspecified thread. Multiple functions + // added to the same Env may run concurrently in different threads. + // I.e., the caller may not assume that background work items are + // serialized. + virtual void Schedule( + void (*function)(void* arg), + void* arg) = 0; + + // Start a new thread, invoking "function(arg)" within the new thread. + // When "function(arg)" returns, the thread will be destroyed. + virtual void StartThread(void (*function)(void* arg), void* arg) = 0; + + // *path is set to a temporary directory that can be used for testing. It may + // or many not have just been created. The directory may or may not differ + // between runs of the same process, but subsequent calls will return the + // same directory. + virtual Status GetTestDirectory(std::string* path) = 0; + + // Create and return a log file for storing informational messages. + virtual Status NewLogger(const std::string& fname, Logger** result) = 0; + + // Returns the number of micro-seconds since some fixed point in time. Only + // useful for computing deltas of time. + virtual uint64_t NowMicros() = 0; + + // Sleep/delay the thread for the perscribed number of micro-seconds. + virtual void SleepForMicroseconds(int micros) = 0; + + private: + // No copying allowed + Env(const Env&); + void operator=(const Env&); +}; + +// A file abstraction for reading sequentially through a file +class SequentialFile { + public: + SequentialFile() { } + virtual ~SequentialFile(); + + // Read up to "n" bytes from the file. "scratch[0..n-1]" may be + // written by this routine. Sets "*result" to the data that was + // read (including if fewer than "n" bytes were successfully read). + // May set "*result" to point at data in "scratch[0..n-1]", so + // "scratch[0..n-1]" must be live when "*result" is used. + // If an error was encountered, returns a non-OK status. + // + // REQUIRES: External synchronization + virtual Status Read(size_t n, Slice* result, char* scratch) = 0; + + // Skip "n" bytes from the file. This is guaranteed to be no + // slower that reading the same data, but may be faster. + // + // If end of file is reached, skipping will stop at the end of the + // file, and Skip will return OK. + // + // REQUIRES: External synchronization + virtual Status Skip(uint64_t n) = 0; + + private: + // No copying allowed + SequentialFile(const SequentialFile&); + void operator=(const SequentialFile&); +}; + +// A file abstraction for randomly reading the contents of a file. +class RandomAccessFile { + public: + RandomAccessFile() { } + virtual ~RandomAccessFile(); + + // Read up to "n" bytes from the file starting at "offset". + // "scratch[0..n-1]" may be written by this routine. Sets "*result" + // to the data that was read (including if fewer than "n" bytes were + // successfully read). May set "*result" to point at data in + // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when + // "*result" is used. If an error was encountered, returns a non-OK + // status. + // + // Safe for concurrent use by multiple threads. + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const = 0; + + private: + // No copying allowed + RandomAccessFile(const RandomAccessFile&); + void operator=(const RandomAccessFile&); +}; + +// A file abstraction for sequential writing. The implementation +// must provide buffering since callers may append small fragments +// at a time to the file. +class WritableFile { + public: + WritableFile() { } + virtual ~WritableFile(); + + virtual Status Append(const Slice& data) = 0; + virtual Status Close() = 0; + virtual Status Flush() = 0; + virtual Status Sync() = 0; + + private: + // No copying allowed + WritableFile(const WritableFile&); + void operator=(const WritableFile&); +}; + +// An interface for writing log messages. +class Logger { + public: + Logger() { } + virtual ~Logger(); + + // Write an entry to the log file with the specified format. + virtual void Logv(const char* format, va_list ap) = 0; + + private: + // No copying allowed + Logger(const Logger&); + void operator=(const Logger&); +}; + + +// Identifies a locked file. +class FileLock { + public: + FileLock() { } + virtual ~FileLock(); + private: + // No copying allowed + FileLock(const FileLock&); + void operator=(const FileLock&); +}; + +// Log the specified data to *info_log if info_log is non-NULL. +extern void Log(Logger* info_log, const char* format, ...) +# if defined(__GNUC__) || defined(__clang__) + __attribute__((__format__ (__printf__, 2, 3))) +# endif + ; + +// A utility routine: write "data" to the named file. +extern Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname); + +// A utility routine: read contents of named file into *data +extern Status ReadFileToString(Env* env, const std::string& fname, + std::string* data); + +// An implementation of Env that forwards all calls to another Env. +// May be useful to clients who wish to override just part of the +// functionality of another Env. +class EnvWrapper : public Env { + public: + // Initialize an EnvWrapper that delegates all calls to *t + explicit EnvWrapper(Env* t) : target_(t) { } + virtual ~EnvWrapper(); + + // Return the target to which this Env forwards all calls + Env* target() const { return target_; } + + // The following text is boilerplate that forwards all methods to target() + Status NewSequentialFile(const std::string& f, SequentialFile** r) { + return target_->NewSequentialFile(f, r); + } + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + return target_->NewRandomAccessFile(f, r); + } + Status NewWritableFile(const std::string& f, WritableFile** r) { + return target_->NewWritableFile(f, r); + } + bool FileExists(const std::string& f) { return target_->FileExists(f); } + Status GetChildren(const std::string& dir, std::vector* r) { + return target_->GetChildren(dir, r); + } + Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); } + Status CreateDir(const std::string& d) { return target_->CreateDir(d); } + Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); } + Status GetFileSize(const std::string& f, uint64_t* s) { + return target_->GetFileSize(f, s); + } + Status RenameFile(const std::string& s, const std::string& t) { + return target_->RenameFile(s, t); + } + Status LockFile(const std::string& f, FileLock** l) { + return target_->LockFile(f, l); + } + Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); } + void Schedule(void (*f)(void*), void* a) { + return target_->Schedule(f, a); + } + void StartThread(void (*f)(void*), void* a) { + return target_->StartThread(f, a); + } + virtual Status GetTestDirectory(std::string* path) { + return target_->GetTestDirectory(path); + } + virtual Status NewLogger(const std::string& fname, Logger** result) { + return target_->NewLogger(fname, result); + } + uint64_t NowMicros() { + return target_->NowMicros(); + } + void SleepForMicroseconds(int micros) { + target_->SleepForMicroseconds(micros); + } + private: + Env* target_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/include/leveldb/filter_policy.h b/include/leveldb/filter_policy.h new file mode 100644 index 000000000..1fba08001 --- /dev/null +++ b/include/leveldb/filter_policy.h @@ -0,0 +1,70 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A database can be configured with a custom FilterPolicy object. +// This object is responsible for creating a small filter from a set +// of keys. These filters are stored in leveldb and are consulted +// automatically by leveldb to decide whether or not to read some +// information from disk. In many cases, a filter can cut down the +// number of disk seeks form a handful to a single disk seek per +// DB::Get() call. +// +// Most people will want to use the builtin bloom filter support (see +// NewBloomFilterPolicy() below). + +#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ +#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ + +#include + +namespace leveldb { + +class Slice; + +class FilterPolicy { + public: + virtual ~FilterPolicy(); + + // Return the name of this policy. Note that if the filter encoding + // changes in an incompatible way, the name returned by this method + // must be changed. Otherwise, old incompatible filters may be + // passed to methods of this type. + virtual const char* Name() const = 0; + + // keys[0,n-1] contains a list of keys (potentially with duplicates) + // that are ordered according to the user supplied comparator. + // Append a filter that summarizes keys[0,n-1] to *dst. + // + // Warning: do not change the initial contents of *dst. Instead, + // append the newly constructed filter to *dst. + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) + const = 0; + + // "filter" contains the data appended by a preceding call to + // CreateFilter() on this class. This method must return true if + // the key was in the list of keys passed to CreateFilter(). + // This method may return true or false if the key was not on the + // list, but it should aim to return false with a high probability. + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; +}; + +// Return a new filter policy that uses a bloom filter with approximately +// the specified number of bits per key. A good value for bits_per_key +// is 10, which yields a filter with ~ 1% false positive rate. +// +// Callers must delete the result after any database that is using the +// result has been closed. +// +// Note: if you are using a custom comparator that ignores some parts +// of the keys being compared, you must not use NewBloomFilterPolicy() +// and must provide your own FilterPolicy that also ignores the +// corresponding parts of the keys. For example, if the comparator +// ignores trailing spaces, it would be incorrect to use a +// FilterPolicy (like NewBloomFilterPolicy) that does not ignore +// trailing spaces in keys. +extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); + +} + +#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/include/leveldb/iterator.h b/include/leveldb/iterator.h new file mode 100644 index 000000000..ad543eb46 --- /dev/null +++ b/include/leveldb/iterator.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An iterator yields a sequence of key/value pairs from a source. +// The following class defines the interface. Multiple implementations +// are provided by this library. In particular, iterators are provided +// to access the contents of a Table or a DB. +// +// Multiple threads can invoke const methods on an Iterator without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Iterator must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ + +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class Iterator { + public: + Iterator(); + virtual ~Iterator(); + + // An iterator is either positioned at a key/value pair, or + // not valid. This method returns true iff the iterator is valid. + virtual bool Valid() const = 0; + + // Position at the first key in the source. The iterator is Valid() + // after this call iff the source is not empty. + virtual void SeekToFirst() = 0; + + // Position at the last key in the source. The iterator is + // Valid() after this call iff the source is not empty. + virtual void SeekToLast() = 0; + + // Position at the first key in the source that at or past target + // The iterator is Valid() after this call iff the source contains + // an entry that comes at or past target. + virtual void Seek(const Slice& target) = 0; + + // Moves to the next entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the last entry in the source. + // REQUIRES: Valid() + virtual void Next() = 0; + + // Moves to the previous entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the first entry in source. + // REQUIRES: Valid() + virtual void Prev() = 0; + + // Return the key for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice key() const = 0; + + // Return the value for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: !AtEnd() && !AtStart() + virtual Slice value() const = 0; + + // If an error has occurred, return it. Else return an ok status. + virtual Status status() const = 0; + + // Clients are allowed to register function/arg1/arg2 triples that + // will be invoked when this iterator is destroyed. + // + // Note that unlike all of the preceding methods, this method is + // not abstract and therefore clients should not override it. + typedef void (*CleanupFunction)(void* arg1, void* arg2); + void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); + + private: + struct Cleanup { + CleanupFunction function; + void* arg1; + void* arg2; + Cleanup* next; + }; + Cleanup cleanup_; + + // No copying allowed + Iterator(const Iterator&); + void operator=(const Iterator&); +}; + +// Return an empty iterator (yields nothing). +extern Iterator* NewEmptyIterator(); + +// Return an empty iterator with the specified status. +extern Iterator* NewErrorIterator(const Status& status); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/include/leveldb/options.h b/include/leveldb/options.h new file mode 100644 index 000000000..fdda718d3 --- /dev/null +++ b/include/leveldb/options.h @@ -0,0 +1,195 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ +#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ + +#include + +namespace leveldb { + +class Cache; +class Comparator; +class Env; +class FilterPolicy; +class Logger; +class Snapshot; + +// DB contents are stored in a set of blocks, each of which holds a +// sequence of key,value pairs. Each block may be compressed before +// being stored in a file. The following enum describes which +// compression method (if any) is used to compress a block. +enum CompressionType { + // NOTE: do not change the values of existing entries, as these are + // part of the persistent format on disk. + kNoCompression = 0x0, + kSnappyCompression = 0x1 +}; + +// Options to control the behavior of a database (passed to DB::Open) +struct Options { + // ------------------- + // Parameters that affect behavior + + // Comparator used to define the order of keys in the table. + // Default: a comparator that uses lexicographic byte-wise ordering + // + // REQUIRES: The client must ensure that the comparator supplied + // here has the same name and orders keys *exactly* the same as the + // comparator provided to previous open calls on the same DB. + const Comparator* comparator; + + // If true, the database will be created if it is missing. + // Default: false + bool create_if_missing; + + // If true, an error is raised if the database already exists. + // Default: false + bool error_if_exists; + + // If true, the implementation will do aggressive checking of the + // data it is processing and will stop early if it detects any + // errors. This may have unforeseen ramifications: for example, a + // corruption of one DB entry may cause a large number of entries to + // become unreadable or for the entire DB to become unopenable. + // Default: false + bool paranoid_checks; + + // Use the specified object to interact with the environment, + // e.g. to read/write files, schedule background work, etc. + // Default: Env::Default() + Env* env; + + // Any internal progress/error information generated by the db will + // be written to info_log if it is non-NULL, or to a file stored + // in the same directory as the DB contents if info_log is NULL. + // Default: NULL + Logger* info_log; + + // ------------------- + // Parameters that affect performance + + // Amount of data to build up in memory (backed by an unsorted log + // on disk) before converting to a sorted on-disk file. + // + // Larger values increase performance, especially during bulk loads. + // Up to two write buffers may be held in memory at the same time, + // so you may wish to adjust this parameter to control memory usage. + // Also, a larger write buffer will result in a longer recovery time + // the next time the database is opened. + // + // Default: 4MB + size_t write_buffer_size; + + // Number of open files that can be used by the DB. You may need to + // increase this if your database has a large working set (budget + // one open file per 2MB of working set). + // + // Default: 1000 + int max_open_files; + + // Control over blocks (user data is stored in a set of blocks, and + // a block is the unit of reading from disk). + + // If non-NULL, use the specified cache for blocks. + // If NULL, leveldb will automatically create and use an 8MB internal cache. + // Default: NULL + Cache* block_cache; + + // Approximate size of user data packed per block. Note that the + // block size specified here corresponds to uncompressed data. The + // actual size of the unit read from disk may be smaller if + // compression is enabled. This parameter can be changed dynamically. + // + // Default: 4K + size_t block_size; + + // Number of keys between restart points for delta encoding of keys. + // This parameter can be changed dynamically. Most clients should + // leave this parameter alone. + // + // Default: 16 + int block_restart_interval; + + // Compress blocks using the specified compression algorithm. This + // parameter can be changed dynamically. + // + // Default: kSnappyCompression, which gives lightweight but fast + // compression. + // + // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: + // ~200-500MB/s compression + // ~400-800MB/s decompression + // Note that these speeds are significantly faster than most + // persistent storage speeds, and therefore it is typically never + // worth switching to kNoCompression. Even if the input data is + // incompressible, the kSnappyCompression implementation will + // efficiently detect that and will switch to uncompressed mode. + CompressionType compression; + + // If non-NULL, use the specified filter policy to reduce disk reads. + // Many applications will benefit from passing the result of + // NewBloomFilterPolicy() here. + // + // Default: NULL + const FilterPolicy* filter_policy; + + // Create an Options object with default values for all fields. + Options(); +}; + +// Options that control read operations +struct ReadOptions { + // If true, all data read from underlying storage will be + // verified against corresponding checksums. + // Default: false + bool verify_checksums; + + // Should the data read for this iteration be cached in memory? + // Callers may wish to set this field to false for bulk scans. + // Default: true + bool fill_cache; + + // If "snapshot" is non-NULL, read as of the supplied snapshot + // (which must belong to the DB that is being read and which must + // not have been released). If "snapshot" is NULL, use an impliicit + // snapshot of the state at the beginning of this read operation. + // Default: NULL + const Snapshot* snapshot; + + ReadOptions() + : verify_checksums(false), + fill_cache(true), + snapshot(NULL) { + } +}; + +// Options that control write operations +struct WriteOptions { + // If true, the write will be flushed from the operating system + // buffer cache (by calling WritableFile::Sync()) before the write + // is considered complete. If this flag is true, writes will be + // slower. + // + // If this flag is false, and the machine crashes, some recent + // writes may be lost. Note that if it is just the process that + // crashes (i.e., the machine does not reboot), no writes will be + // lost even if sync==false. + // + // In other words, a DB write with sync==false has similar + // crash semantics as the "write()" system call. A DB write + // with sync==true has similar crash semantics to a "write()" + // system call followed by "fsync()". + // + // Default: false + bool sync; + + WriteOptions() + : sync(false) { + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/include/leveldb/slice.h b/include/leveldb/slice.h new file mode 100644 index 000000000..74ea8fa49 --- /dev/null +++ b/include/leveldb/slice.h @@ -0,0 +1,109 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Slice is a simple structure containing a pointer into some external +// storage and a size. The user of a Slice must ensure that the slice +// is not used after the corresponding external storage has been +// deallocated. +// +// Multiple threads can invoke const methods on a Slice without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Slice must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ +#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Slice { + public: + // Create an empty slice. + Slice() : data_(""), size_(0) { } + + // Create a slice that refers to d[0,n-1]. + Slice(const char* d, size_t n) : data_(d), size_(n) { } + + // Create a slice that refers to the contents of "s" + Slice(const std::string& s) : data_(s.data()), size_(s.size()) { } + + // Create a slice that refers to s[0,strlen(s)-1] + Slice(const char* s) : data_(s), size_(strlen(s)) { } + + // Return a pointer to the beginning of the referenced data + const char* data() const { return data_; } + + // Return the length (in bytes) of the referenced data + size_t size() const { return size_; } + + // Return true iff the length of the referenced data is zero + bool empty() const { return size_ == 0; } + + // Return the ith byte in the referenced data. + // REQUIRES: n < size() + char operator[](size_t n) const { + assert(n < size()); + return data_[n]; + } + + // Change this slice to refer to an empty array + void clear() { data_ = ""; size_ = 0; } + + // Drop the first "n" bytes from this slice. + void remove_prefix(size_t n) { + assert(n <= size()); + data_ += n; + size_ -= n; + } + + // Return a string that contains the copy of the referenced data. + std::string ToString() const { return std::string(data_, size_); } + + // Three-way comparison. Returns value: + // < 0 iff "*this" < "b", + // == 0 iff "*this" == "b", + // > 0 iff "*this" > "b" + int compare(const Slice& b) const; + + // Return true iff "x" is a prefix of "*this" + bool starts_with(const Slice& x) const { + return ((size_ >= x.size_) && + (memcmp(data_, x.data_, x.size_) == 0)); + } + + private: + const char* data_; + size_t size_; + + // Intentionally copyable +}; + +inline bool operator==(const Slice& x, const Slice& y) { + return ((x.size() == y.size()) && + (memcmp(x.data(), y.data(), x.size()) == 0)); +} + +inline bool operator!=(const Slice& x, const Slice& y) { + return !(x == y); +} + +inline int Slice::compare(const Slice& b) const { + const int min_len = (size_ < b.size_) ? size_ : b.size_; + int r = memcmp(data_, b.data_, min_len); + if (r == 0) { + if (size_ < b.size_) r = -1; + else if (size_ > b.size_) r = +1; + } + return r; +} + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/include/leveldb/status.h b/include/leveldb/status.h new file mode 100644 index 000000000..11dbd4b47 --- /dev/null +++ b/include/leveldb/status.h @@ -0,0 +1,106 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Status encapsulates the result of an operation. It may indicate success, +// or it may indicate an error with an associated error message. +// +// Multiple threads can invoke const methods on a Status without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Status must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ +#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Status { + public: + // Create a success status. + Status() : state_(NULL) { } + ~Status() { delete[] state_; } + + // Copy the specified status. + Status(const Status& s); + void operator=(const Status& s); + + // Return a success status. + static Status OK() { return Status(); } + + // Return error status of an appropriate type. + static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotFound, msg, msg2); + } + static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kCorruption, msg, msg2); + } + static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotSupported, msg, msg2); + } + static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kInvalidArgument, msg, msg2); + } + static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kIOError, msg, msg2); + } + + // Returns true iff the status indicates success. + bool ok() const { return (state_ == NULL); } + + // Returns true iff the status indicates a NotFound error. + bool IsNotFound() const { return code() == kNotFound; } + + // Returns true iff the status indicates a Corruption error. + bool IsCorruption() const { return code() == kCorruption; } + + // Returns true iff the status indicates an IOError. + bool IsIOError() const { return code() == kIOError; } + + // Return a string representation of this status suitable for printing. + // Returns the string "OK" for success. + std::string ToString() const; + + private: + // OK status has a NULL state_. Otherwise, state_ is a new[] array + // of the following form: + // state_[0..3] == length of message + // state_[4] == code + // state_[5..] == message + const char* state_; + + enum Code { + kOk = 0, + kNotFound = 1, + kCorruption = 2, + kNotSupported = 3, + kInvalidArgument = 4, + kIOError = 5 + }; + + Code code() const { + return (state_ == NULL) ? kOk : static_cast(state_[4]); + } + + Status(Code code, const Slice& msg, const Slice& msg2); + static const char* CopyState(const char* s); +}; + +inline Status::Status(const Status& s) { + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); +} +inline void Status::operator=(const Status& s) { + // The following condition catches both aliasing (when this == &s), + // and the common case where both s and *this are ok. + if (state_ != s.state_) { + delete[] state_; + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/include/leveldb/table.h b/include/leveldb/table.h new file mode 100644 index 000000000..a9746c3f5 --- /dev/null +++ b/include/leveldb/table.h @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ + +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +class Block; +class BlockHandle; +class Footer; +struct Options; +class RandomAccessFile; +struct ReadOptions; +class TableCache; + +// A Table is a sorted map from strings to strings. Tables are +// immutable and persistent. A Table may be safely accessed from +// multiple threads without external synchronization. +class Table { + public: + // Attempt to open the table that is stored in bytes [0..file_size) + // of "file", and read the metadata entries necessary to allow + // retrieving data from the table. + // + // If successful, returns ok and sets "*table" to the newly opened + // table. The client should delete "*table" when no longer needed. + // If there was an error while initializing the table, sets "*table" + // to NULL and returns a non-ok status. Does not take ownership of + // "*source", but the client must ensure that "source" remains live + // for the duration of the returned table's lifetime. + // + // *file must remain live while this Table is in use. + static Status Open(const Options& options, + RandomAccessFile* file, + uint64_t file_size, + Table** table); + + ~Table(); + + // Returns a new iterator over the table contents. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + Iterator* NewIterator(const ReadOptions&) const; + + // Given a key, return an approximate byte offset in the file where + // the data for that key begins (or would begin if the key were + // present in the file). The returned value is in terms of file + // bytes, and so includes effects like compression of the underlying data. + // E.g., the approximate offset of the last key in the table will + // be close to the file length. + uint64_t ApproximateOffsetOf(const Slice& key) const; + + private: + struct Rep; + Rep* rep_; + + explicit Table(Rep* rep) { rep_ = rep; } + static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); + + // Calls (*handle_result)(arg, ...) with the entry found after a call + // to Seek(key). May not make such a call if filter policy says + // that key is not present. + friend class TableCache; + Status InternalGet( + const ReadOptions&, const Slice& key, + void* arg, + void (*handle_result)(void* arg, const Slice& k, const Slice& v)); + + + void ReadMeta(const Footer& footer); + void ReadFilter(const Slice& filter_handle_value); + + // No copying allowed + Table(const Table&); + void operator=(const Table&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/include/leveldb/table_builder.h b/include/leveldb/table_builder.h new file mode 100644 index 000000000..5fd1dc71f --- /dev/null +++ b/include/leveldb/table_builder.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// TableBuilder provides the interface used to build a Table +// (an immutable and sorted map from keys to values). +// +// Multiple threads can invoke const methods on a TableBuilder without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same TableBuilder must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ + +#include +#include "leveldb/options.h" +#include "leveldb/status.h" + +namespace leveldb { + +class BlockBuilder; +class BlockHandle; +class WritableFile; + +class TableBuilder { + public: + // Create a builder that will store the contents of the table it is + // building in *file. Does not close the file. It is up to the + // caller to close the file after calling Finish(). + TableBuilder(const Options& options, WritableFile* file); + + // REQUIRES: Either Finish() or Abandon() has been called. + ~TableBuilder(); + + // Change the options used by this builder. Note: only some of the + // option fields can be changed after construction. If a field is + // not allowed to change dynamically and its value in the structure + // passed to the constructor is different from its value in the + // structure passed to this method, this method will return an error + // without changing any fields. + Status ChangeOptions(const Options& options); + + // Add key,value to the table being constructed. + // REQUIRES: key is after any previously added key according to comparator. + // REQUIRES: Finish(), Abandon() have not been called + void Add(const Slice& key, const Slice& value); + + // Advanced operation: flush any buffered key/value pairs to file. + // Can be used to ensure that two adjacent entries never live in + // the same data block. Most clients should not need to use this method. + // REQUIRES: Finish(), Abandon() have not been called + void Flush(); + + // Return non-ok iff some error has been detected. + Status status() const; + + // Finish building the table. Stops using the file passed to the + // constructor after this function returns. + // REQUIRES: Finish(), Abandon() have not been called + Status Finish(); + + // Indicate that the contents of this builder should be abandoned. Stops + // using the file passed to the constructor after this function returns. + // If the caller is not going to call Finish(), it must call Abandon() + // before destroying this builder. + // REQUIRES: Finish(), Abandon() have not been called + void Abandon(); + + // Number of calls to Add() so far. + uint64_t NumEntries() const; + + // Size of the file generated so far. If invoked after a successful + // Finish() call, returns the size of the final generated file. + uint64_t FileSize() const; + + private: + bool ok() const { return status().ok(); } + void WriteBlock(BlockBuilder* block, BlockHandle* handle); + void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); + + struct Rep; + Rep* rep_; + + // No copying allowed + TableBuilder(const TableBuilder&); + void operator=(const TableBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/include/leveldb/write_batch.h b/include/leveldb/write_batch.h new file mode 100644 index 000000000..ee9aab68e --- /dev/null +++ b/include/leveldb/write_batch.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch holds a collection of updates to apply atomically to a DB. +// +// The updates are applied in the order in which they are added +// to the WriteBatch. For example, the value of "key" will be "v3" +// after the following batch is written: +// +// batch.Put("key", "v1"); +// batch.Delete("key"); +// batch.Put("key", "v2"); +// batch.Put("key", "v3"); +// +// Multiple threads can invoke const methods on a WriteBatch without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same WriteBatch must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ +#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ + +#include +#include "leveldb/status.h" + +namespace leveldb { + +class Slice; + +class WriteBatch { + public: + WriteBatch(); + ~WriteBatch(); + + // Store the mapping "key->value" in the database. + void Put(const Slice& key, const Slice& value); + + // If the database contains a mapping for "key", erase it. Else do nothing. + void Delete(const Slice& key); + + // Clear all updates buffered in this batch. + void Clear(); + + // Support for iterating over the contents of a batch. + class Handler { + public: + virtual ~Handler(); + virtual void Put(const Slice& key, const Slice& value) = 0; + virtual void Delete(const Slice& key) = 0; + }; + Status Iterate(Handler* handler) const; + + private: + friend class WriteBatchInternal; + + std::string rep_; // See comment in write_batch.cc for the format of rep_ + + // Intentionally copyable +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/port/README b/port/README new file mode 100644 index 000000000..422563e25 --- /dev/null +++ b/port/README @@ -0,0 +1,10 @@ +This directory contains interfaces and implementations that isolate the +rest of the package from platform details. + +Code in the rest of the package includes "port.h" from this directory. +"port.h" in turn includes a platform specific "port_.h" file +that provides the platform specific implementation. + +See port_posix.h for an example of what must be provided in a platform +specific header file. + diff --git a/port/atomic_pointer.h b/port/atomic_pointer.h new file mode 100644 index 000000000..e17bf435e --- /dev/null +++ b/port/atomic_pointer.h @@ -0,0 +1,224 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// AtomicPointer provides storage for a lock-free pointer. +// Platform-dependent implementation of AtomicPointer: +// - If the platform provides a cheap barrier, we use it with raw pointers +// - If cstdatomic is present (on newer versions of gcc, it is), we use +// a cstdatomic-based AtomicPointer. However we prefer the memory +// barrier based version, because at least on a gcc 4.4 32-bit build +// on linux, we have encountered a buggy +// implementation. Also, some implementations are much +// slower than a memory-barrier based implementation (~16ns for +// based acquire-load vs. ~1ns for a barrier based +// acquire-load). +// This code is based on atomicops-internals-* in Google's perftools: +// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase + +#ifndef PORT_ATOMIC_POINTER_H_ +#define PORT_ATOMIC_POINTER_H_ + +#include +#ifdef LEVELDB_CSTDATOMIC_PRESENT +#include +#endif +#ifdef OS_WIN +#include +#endif +#ifdef OS_MACOSX +#include +#endif + +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) +#define ARCH_CPU_PPC_FAMILY 1 +#endif + +namespace leveldb { +namespace port { + +// Define MemoryBarrier() if available +// Windows on x86 +#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) +// windows.h already provides a MemoryBarrier(void) macro +// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Gcc on x86 +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + __asm__ __volatile__("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Sun Studio +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + asm volatile("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Mac OS +#elif defined(OS_MACOSX) +inline void MemoryBarrier() { + OSMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// ARM Linux +#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +// The Linux ARM kernel provides a highly optimized device-specific memory +// barrier function at a fixed memory address that is mapped in every +// user-level process. +// +// This beats using CPU-specific instructions which are, on single-core +// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more +// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking +// shows that the extra function call cost is completely negligible on +// multi-core devices. +// +inline void MemoryBarrier() { + (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// PPC +#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // TODO for some powerpc expert: is there a cheaper suitable variant? + // Perhaps by having separate barriers for acquire and release ops. + asm volatile("sync" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +#endif + +// AtomicPointer built using platform-specific MemoryBarrier() +#if defined(LEVELDB_HAVE_MEMORY_BARRIER) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* p) : rep_(p) {} + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } + inline void* Acquire_Load() const { + void* result = rep_; + MemoryBarrier(); + return result; + } + inline void Release_Store(void* v) { + MemoryBarrier(); + rep_ = v; + } +}; + +// AtomicPointer based on +#elif defined(LEVELDB_CSTDATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +// Atomic pointer based on sparc memory barriers +#elif defined(__sparcv9) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val; + __asm__ __volatile__ ( + "ldx [%[rep_]], %[val] \n\t" + "membar #LoadLoad|#LoadStore \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory"); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "membar #LoadStore|#StoreStore \n\t" + "stx %[v], [%[rep_]] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory"); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// Atomic pointer based on ia64 acq/rel +#elif defined(__ia64) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val ; + __asm__ __volatile__ ( + "ld8.acq %[val] = [%[rep_]] \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory" + ); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "st8.rel [%[rep_]] = %[v] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory" + ); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// We have neither MemoryBarrier(), nor +#else +#error Please implement AtomicPointer for this platform. + +#endif + +#undef LEVELDB_HAVE_MEMORY_BARRIER +#undef ARCH_CPU_X86_FAMILY +#undef ARCH_CPU_ARM_FAMILY +#undef ARCH_CPU_PPC_FAMILY + +} // namespace port +} // namespace leveldb + +#endif // PORT_ATOMIC_POINTER_H_ diff --git a/port/port.h b/port/port.h new file mode 100644 index 000000000..4baafa8e2 --- /dev/null +++ b/port/port.h @@ -0,0 +1,21 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_H_ +#define STORAGE_LEVELDB_PORT_PORT_H_ + +#include + +// Include the appropriate platform specific file below. If you are +// porting to a new platform, see "port_example.h" for documentation +// of what the new port_.h file must provide. +#if defined(LEVELDB_PLATFORM_POSIX) +# include "port/port_posix.h" +#elif defined(LEVELDB_PLATFORM_CHROMIUM) +# include "port/port_chromium.h" +#elif defined(LEVELDB_PLATFORM_WINDOWS) +# include "port/port_win.h" +#endif + +#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/port/port_example.h b/port/port_example.h new file mode 100644 index 000000000..ab9e489b3 --- /dev/null +++ b/port/port_example.h @@ -0,0 +1,135 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// This file contains the specification, but not the implementations, +// of the types/operations/etc. that should be defined by a platform +// specific port_.h file. Use this file as a reference for +// how to port this package to a new platform. + +#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ +#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ + +namespace leveldb { +namespace port { + +// TODO(jorlow): Many of these belong more in the environment class rather than +// here. We should try moving them and see if it affects perf. + +// The following boolean constant must be true on a little-endian machine +// and false otherwise. +static const bool kLittleEndian = true /* or some other expression */; + +// ------------------ Threading ------------------- + +// A Mutex represents an exclusive lock. +class Mutex { + public: + Mutex(); + ~Mutex(); + + // Lock the mutex. Waits until other lockers have exited. + // Will deadlock if the mutex is already locked by this thread. + void Lock(); + + // Unlock the mutex. + // REQUIRES: This mutex was locked by this thread. + void Unlock(); + + // Optionally crash if this thread does not hold this mutex. + // The implementation must be fast, especially if NDEBUG is + // defined. The implementation is allowed to skip all checks. + void AssertHeld(); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + + // Atomically release *mu and block on this condition variable until + // either a call to SignalAll(), or a call to Signal() that picks + // this thread to wakeup. + // REQUIRES: this thread holds *mu + void Wait(); + + // If there are some threads waiting, wake up at least one of them. + void Signal(); + + // Wake up all waiting threads. + void SignallAll(); +}; + +// Thread-safe initialization. +// Used as follows: +// static port::OnceType init_control = LEVELDB_ONCE_INIT; +// static void Initializer() { ... do something ...; } +// ... +// port::InitOnce(&init_control, &Initializer); +typedef intptr_t OnceType; +#define LEVELDB_ONCE_INIT 0 +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// A type that holds a pointer that can be read or written atomically +// (i.e., without word-tearing.) +class AtomicPointer { + private: + intptr_t rep_; + public: + // Initialize to arbitrary value + AtomicPointer(); + + // Initialize to hold v + explicit AtomicPointer(void* v) : rep_(v) { } + + // Read and return the stored pointer with the guarantee that no + // later memory access (read or write) by this thread can be + // reordered ahead of this read. + void* Acquire_Load() const; + + // Set v as the stored pointer with the guarantee that no earlier + // memory access (read or write) by this thread can be reordered + // after this store. + void Release_Store(void* v); + + // Read the stored pointer with no ordering guarantees. + void* NoBarrier_Load() const; + + // Set va as the stored pointer with no ordering guarantees. + void NoBarrier_Store(void* v); +}; + +// ------------------ Compression ------------------- + +// Store the snappy compression of "input[0,input_length-1]" in *output. +// Returns false if snappy is not supported by this port. +extern bool Snappy_Compress(const char* input, size_t input_length, + std::string* output); + +// If input[0,input_length-1] looks like a valid snappy compressed +// buffer, store the size of the uncompressed data in *result and +// return true. Else return false. +extern bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result); + +// Attempt to snappy uncompress input[0,input_length-1] into *output. +// Returns true if successful, false if the input is invalid lightweight +// compressed data. +// +// REQUIRES: at least the first "n" bytes of output[] must be writable +// where "n" is the result of a successful call to +// Snappy_GetUncompressedLength. +extern bool Snappy_Uncompress(const char* input_data, size_t input_length, + char* output); + +// ------------------ Miscellaneous ------------------- + +// If heap profiling is not supported, returns false. +// Else repeatedly calls (*func)(arg, data, n) and then returns true. +// The concatenation of all "data[0,n-1]" fragments is the heap profile. +extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/port/port_posix.cc b/port/port_posix.cc new file mode 100644 index 000000000..5ba127a5b --- /dev/null +++ b/port/port_posix.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "port/port_posix.h" + +#include +#include +#include +#include "util/logging.h" + +namespace leveldb { +namespace port { + +static void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } +} + +Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); } + +Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } + +void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } + +void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } + +CondVar::CondVar(Mutex* mu) + : mu_(mu) { + PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); +} + +CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } + +void CondVar::Wait() { + PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); +} + +void CondVar::Signal() { + PthreadCall("signal", pthread_cond_signal(&cv_)); +} + +void CondVar::SignalAll() { + PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + PthreadCall("once", pthread_once(once, initializer)); +} + +} // namespace port +} // namespace leveldb diff --git a/port/port_posix.h b/port/port_posix.h new file mode 100644 index 000000000..f2b89bffb --- /dev/null +++ b/port/port_posix.h @@ -0,0 +1,157 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ +#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ + +#undef PLATFORM_IS_LITTLE_ENDIAN +#if defined(OS_MACOSX) + #include + #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER) + #define PLATFORM_IS_LITTLE_ENDIAN \ + (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN) + #endif +#elif defined(OS_SOLARIS) + #include + #ifdef _LITTLE_ENDIAN + #define PLATFORM_IS_LITTLE_ENDIAN true + #else + #define PLATFORM_IS_LITTLE_ENDIAN false + #endif +#elif defined(OS_FREEBSD) + #include + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\ + defined(OS_DRAGONFLYBSD) + #include + #include +#elif defined(OS_HPUX) + #define PLATFORM_IS_LITTLE_ENDIAN false +#elif defined(OS_ANDROID) + // Due to a bug in the NDK x86 definition, + // _BYTE_ORDER must be used instead of __BYTE_ORDER on Android. + // See http://code.google.com/p/android/issues/detail?id=39824 + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#else + #include +#endif + +#include +#ifdef SNAPPY +#include +#endif +#include +#include +#include "port/atomic_pointer.h" + +#ifndef PLATFORM_IS_LITTLE_ENDIAN +#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) +#endif + +#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ + defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ + defined(OS_ANDROID) || defined(OS_HPUX) +// Use fread/fwrite/fflush on platforms without _unlocked variants +#define fread_unlocked fread +#define fwrite_unlocked fwrite +#define fflush_unlocked fflush +#endif + +#if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\ + defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) +// Use fsync() on platforms without fdatasync() +#define fdatasync fsync +#endif + +#if defined(OS_ANDROID) && __ANDROID_API__ < 9 +// fdatasync() was only introduced in API level 9 on Android. Use fsync() +// when targetting older platforms. +#define fdatasync fsync +#endif + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN; +#undef PLATFORM_IS_LITTLE_ENDIAN + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld() { } + + private: + friend class CondVar; + pthread_mutex_t mu_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + pthread_cond_t cv_; + Mutex* mu_; +}; + +typedef pthread_once_t OnceType; +#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT +extern void InitOnce(OnceType* once, void (*initializer)()); + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/port/port_win.cc b/port/port_win.cc new file mode 100644 index 000000000..99c1d8e34 --- /dev/null +++ b/port/port_win.cc @@ -0,0 +1,149 @@ +// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "port/port_win.h" + +#include +#include + +namespace leveldb { +namespace port { + +Mutex::Mutex() : + cs_(NULL) { + assert(!cs_); + cs_ = static_cast(new CRITICAL_SECTION()); + ::InitializeCriticalSection(static_cast(cs_)); + assert(cs_); +} + +Mutex::~Mutex() { + assert(cs_); + ::DeleteCriticalSection(static_cast(cs_)); + delete static_cast(cs_); + cs_ = NULL; + assert(!cs_); +} + +void Mutex::Lock() { + assert(cs_); + ::EnterCriticalSection(static_cast(cs_)); +} + +void Mutex::Unlock() { + assert(cs_); + ::LeaveCriticalSection(static_cast(cs_)); +} + +void Mutex::AssertHeld() { + assert(cs_); + assert(1); +} + +CondVar::CondVar(Mutex* mu) : + waiting_(0), + mu_(mu), + sem1_(::CreateSemaphore(NULL, 0, 10000, NULL)), + sem2_(::CreateSemaphore(NULL, 0, 10000, NULL)) { + assert(mu_); +} + +CondVar::~CondVar() { + ::CloseHandle(sem1_); + ::CloseHandle(sem2_); +} + +void CondVar::Wait() { + mu_->AssertHeld(); + + wait_mtx_.Lock(); + ++waiting_; + wait_mtx_.Unlock(); + + mu_->Unlock(); + + // initiate handshake + ::WaitForSingleObject(sem1_, INFINITE); + ::ReleaseSemaphore(sem2_, 1, NULL); + mu_->Lock(); +} + +void CondVar::Signal() { + wait_mtx_.Lock(); + if (waiting_ > 0) { + --waiting_; + + // finalize handshake + ::ReleaseSemaphore(sem1_, 1, NULL); + ::WaitForSingleObject(sem2_, INFINITE); + } + wait_mtx_.Unlock(); +} + +void CondVar::SignalAll() { + wait_mtx_.Lock(); + for(long i = 0; i < waiting_; ++i) { + ::ReleaseSemaphore(sem1_, 1, NULL); + while(waiting_ > 0) { + --waiting_; + ::WaitForSingleObject(sem2_, INFINITE); + } + } + wait_mtx_.Unlock(); +} + +AtomicPointer::AtomicPointer(void* v) { + Release_Store(v); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + once->InitOnce(initializer); +} + +void* AtomicPointer::Acquire_Load() const { + void * p = NULL; + InterlockedExchangePointer(&p, rep_); + return p; +} + +void AtomicPointer::Release_Store(void* v) { + InterlockedExchangePointer(&rep_, v); +} + +void* AtomicPointer::NoBarrier_Load() const { + return rep_; +} + +void AtomicPointer::NoBarrier_Store(void* v) { + rep_ = v; +} + +} +} diff --git a/port/port_win.h b/port/port_win.h new file mode 100644 index 000000000..45bf2f0ea --- /dev/null +++ b/port/port_win.h @@ -0,0 +1,174 @@ +// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ +#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ + +#ifdef _MSC_VER +#define snprintf _snprintf +#define close _close +#define fread_unlocked _fread_nolock +#endif + +#include +#include +#ifdef SNAPPY +#include +#endif + +namespace leveldb { +namespace port { + +// Windows is little endian (for now :p) +static const bool kLittleEndian = true; + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld(); + + private: + friend class CondVar; + // critical sections are more efficient than mutexes + // but they are not recursive and can only be used to synchronize threads within the same process + // we use opaque void * to avoid including windows.h in port_win.h + void * cs_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +// the Win32 API offers a dependable condition variable mechanism, but only starting with +// Windows 2008 and Vista +// no matter what we will implement our own condition variable with a semaphore +// implementation as described in a paper written by Andrew D. Birrell in 2003 +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + Mutex* mu_; + + Mutex wait_mtx_; + long waiting_; + + void * sem1_; + void * sem2_; + + +}; + +class OnceType { +public: +// OnceType() : init_(false) {} + OnceType(const OnceType &once) : init_(once.init_) {} + OnceType(bool f) : init_(f) {} + void InitOnce(void (*initializer)()) { + mutex_.Lock(); + if (!init_) { + init_ = true; + initializer(); + } + mutex_.Unlock(); + } + +private: + bool init_; + Mutex mutex_; +}; + +#define LEVELDB_ONCE_INIT false +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// Storage for a lock-free pointer +class AtomicPointer { + private: + void * rep_; + public: + AtomicPointer() : rep_(NULL) { } + explicit AtomicPointer(void* v); + void* Acquire_Load() const; + + void Release_Store(void* v); + + void* NoBarrier_Load() const; + + void NoBarrier_Store(void* v); +}; + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} +} + +#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ diff --git a/port/thread_annotations.h b/port/thread_annotations.h new file mode 100644 index 000000000..6f9b6a792 --- /dev/null +++ b/port/thread_annotations.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H + +// Some environments provide custom macros to aid in static thread-safety +// analysis. Provide empty definitions of such macros unless they are already +// defined. + +#ifndef EXCLUSIVE_LOCKS_REQUIRED +#define EXCLUSIVE_LOCKS_REQUIRED(...) +#endif + +#ifndef SHARED_LOCKS_REQUIRED +#define SHARED_LOCKS_REQUIRED(...) +#endif + +#ifndef LOCKS_EXCLUDED +#define LOCKS_EXCLUDED(...) +#endif + +#ifndef LOCK_RETURNED +#define LOCK_RETURNED(x) +#endif + +#ifndef LOCKABLE +#define LOCKABLE +#endif + +#ifndef SCOPED_LOCKABLE +#define SCOPED_LOCKABLE +#endif + +#ifndef EXCLUSIVE_LOCK_FUNCTION +#define EXCLUSIVE_LOCK_FUNCTION(...) +#endif + +#ifndef SHARED_LOCK_FUNCTION +#define SHARED_LOCK_FUNCTION(...) +#endif + +#ifndef EXCLUSIVE_TRYLOCK_FUNCTION +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) +#endif + +#ifndef SHARED_TRYLOCK_FUNCTION +#define SHARED_TRYLOCK_FUNCTION(...) +#endif + +#ifndef UNLOCK_FUNCTION +#define UNLOCK_FUNCTION(...) +#endif + +#ifndef NO_THREAD_SAFETY_ANALYSIS +#define NO_THREAD_SAFETY_ANALYSIS +#endif + +#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H diff --git a/port/win/stdint.h b/port/win/stdint.h new file mode 100644 index 000000000..39edd0db1 --- /dev/null +++ b/port/win/stdint.h @@ -0,0 +1,24 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// MSVC didn't ship with this file until the 2010 version. + +#ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_ +#define STORAGE_LEVELDB_PORT_WIN_STDINT_H_ + +#if !defined(_MSC_VER) +#error This file should only be included when compiling with MSVC. +#endif + +// Define C99 equivalent types. +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_ diff --git a/table/block.cc b/table/block.cc new file mode 100644 index 000000000..ab83c1112 --- /dev/null +++ b/table/block.cc @@ -0,0 +1,267 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Decodes the blocks generated by block_builder.cc. + +#include "table/block.h" + +#include +#include +#include "leveldb/comparator.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +inline uint32_t Block::NumRestarts() const { + assert(size_ >= 2*sizeof(uint32_t)); + return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); +} + +Block::Block(const BlockContents& contents) + : data_(contents.data.data()), + size_(contents.data.size()), + owned_(contents.heap_allocated) { + if (size_ < sizeof(uint32_t)) { + size_ = 0; // Error marker + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); + if (restart_offset_ > size_ - sizeof(uint32_t)) { + // The size is too small for NumRestarts() and therefore + // restart_offset_ wrapped around. + size_ = 0; + } + } +} + +Block::~Block() { + if (owned_) { + delete[] data_; + } +} + +// Helper routine: decode the next block entry starting at "p", +// storing the number of shared key bytes, non_shared key bytes, +// and the length of the value in "*shared", "*non_shared", and +// "*value_length", respectively. Will not derefence past "limit". +// +// If any errors are detected, returns NULL. Otherwise, returns a +// pointer to the key delta (just past the three decoded values). +static inline const char* DecodeEntry(const char* p, const char* limit, + uint32_t* shared, + uint32_t* non_shared, + uint32_t* value_length) { + if (limit - p < 3) return NULL; + *shared = reinterpret_cast(p)[0]; + *non_shared = reinterpret_cast(p)[1]; + *value_length = reinterpret_cast(p)[2]; + if ((*shared | *non_shared | *value_length) < 128) { + // Fast path: all three values are encoded in one byte each + p += 3; + } else { + if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL; + } + + if (static_cast(limit - p) < (*non_shared + *value_length)) { + return NULL; + } + return p; +} + +class Block::Iter : public Iterator { + private: + const Comparator* const comparator_; + const char* const data_; // underlying block contents + uint32_t const restarts_; // Offset of restart array (list of fixed32) + uint32_t const num_restarts_; // Number of uint32_t entries in restart array + + // current_ is offset in data_ of current entry. >= restarts_ if !Valid + uint32_t current_; + uint32_t restart_index_; // Index of restart block in which current_ falls + std::string key_; + Slice value_; + Status status_; + + inline int Compare(const Slice& a, const Slice& b) const { + return comparator_->Compare(a, b); + } + + // Return the offset in data_ just past the end of the current entry. + inline uint32_t NextEntryOffset() const { + return (value_.data() + value_.size()) - data_; + } + + uint32_t GetRestartPoint(uint32_t index) { + assert(index < num_restarts_); + return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); + } + + void SeekToRestartPoint(uint32_t index) { + key_.clear(); + restart_index_ = index; + // current_ will be fixed by ParseNextKey(); + + // ParseNextKey() starts at the end of value_, so set value_ accordingly + uint32_t offset = GetRestartPoint(index); + value_ = Slice(data_ + offset, 0); + } + + public: + Iter(const Comparator* comparator, + const char* data, + uint32_t restarts, + uint32_t num_restarts) + : comparator_(comparator), + data_(data), + restarts_(restarts), + num_restarts_(num_restarts), + current_(restarts_), + restart_index_(num_restarts_) { + assert(num_restarts_ > 0); + } + + virtual bool Valid() const { return current_ < restarts_; } + virtual Status status() const { return status_; } + virtual Slice key() const { + assert(Valid()); + return key_; + } + virtual Slice value() const { + assert(Valid()); + return value_; + } + + virtual void Next() { + assert(Valid()); + ParseNextKey(); + } + + virtual void Prev() { + assert(Valid()); + + // Scan backwards to a restart point before current_ + const uint32_t original = current_; + while (GetRestartPoint(restart_index_) >= original) { + if (restart_index_ == 0) { + // No more entries + current_ = restarts_; + restart_index_ = num_restarts_; + return; + } + restart_index_--; + } + + SeekToRestartPoint(restart_index_); + do { + // Loop until end of current entry hits the start of original entry + } while (ParseNextKey() && NextEntryOffset() < original); + } + + virtual void Seek(const Slice& target) { + // Binary search in restart array to find the last restart point + // with a key < target + uint32_t left = 0; + uint32_t right = num_restarts_ - 1; + while (left < right) { + uint32_t mid = (left + right + 1) / 2; + uint32_t region_offset = GetRestartPoint(mid); + uint32_t shared, non_shared, value_length; + const char* key_ptr = DecodeEntry(data_ + region_offset, + data_ + restarts_, + &shared, &non_shared, &value_length); + if (key_ptr == NULL || (shared != 0)) { + CorruptionError(); + return; + } + Slice mid_key(key_ptr, non_shared); + if (Compare(mid_key, target) < 0) { + // Key at "mid" is smaller than "target". Therefore all + // blocks before "mid" are uninteresting. + left = mid; + } else { + // Key at "mid" is >= "target". Therefore all blocks at or + // after "mid" are uninteresting. + right = mid - 1; + } + } + + // Linear search (within restart block) for first key >= target + SeekToRestartPoint(left); + while (true) { + if (!ParseNextKey()) { + return; + } + if (Compare(key_, target) >= 0) { + return; + } + } + } + + virtual void SeekToFirst() { + SeekToRestartPoint(0); + ParseNextKey(); + } + + virtual void SeekToLast() { + SeekToRestartPoint(num_restarts_ - 1); + while (ParseNextKey() && NextEntryOffset() < restarts_) { + // Keep skipping + } + } + + private: + void CorruptionError() { + current_ = restarts_; + restart_index_ = num_restarts_; + status_ = Status::Corruption("bad entry in block"); + key_.clear(); + value_.clear(); + } + + bool ParseNextKey() { + current_ = NextEntryOffset(); + const char* p = data_ + current_; + const char* limit = data_ + restarts_; // Restarts come right after data + if (p >= limit) { + // No more entries to return. Mark as invalid. + current_ = restarts_; + restart_index_ = num_restarts_; + return false; + } + + // Decode next entry + uint32_t shared, non_shared, value_length; + p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); + if (p == NULL || key_.size() < shared) { + CorruptionError(); + return false; + } else { + key_.resize(shared); + key_.append(p, non_shared); + value_ = Slice(p + non_shared, value_length); + while (restart_index_ + 1 < num_restarts_ && + GetRestartPoint(restart_index_ + 1) < current_) { + ++restart_index_; + } + return true; + } + } +}; + +Iterator* Block::NewIterator(const Comparator* cmp) { + if (size_ < 2*sizeof(uint32_t)) { + return NewErrorIterator(Status::Corruption("bad block contents")); + } + const uint32_t num_restarts = NumRestarts(); + if (num_restarts == 0) { + return NewEmptyIterator(); + } else { + return new Iter(cmp, data_, restart_offset_, num_restarts); + } +} + +} // namespace leveldb diff --git a/table/block.h b/table/block.h new file mode 100644 index 000000000..2493eb9f9 --- /dev/null +++ b/table/block.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_H_ + +#include +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +struct BlockContents; +class Comparator; + +class Block { + public: + // Initialize the block with the specified contents. + explicit Block(const BlockContents& contents); + + ~Block(); + + size_t size() const { return size_; } + Iterator* NewIterator(const Comparator* comparator); + + private: + uint32_t NumRestarts() const; + + const char* data_; + size_t size_; + uint32_t restart_offset_; // Offset in data_ of restart array + bool owned_; // Block owns data_[] + + // No copying allowed + Block(const Block&); + void operator=(const Block&); + + class Iter; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/table/block_builder.cc b/table/block_builder.cc new file mode 100644 index 000000000..db660cd07 --- /dev/null +++ b/table/block_builder.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// BlockBuilder generates blocks where keys are prefix-compressed: +// +// When we store a key, we drop the prefix shared with the previous +// string. This helps reduce the space requirement significantly. +// Furthermore, once every K keys, we do not apply the prefix +// compression and store the entire key. We call this a "restart +// point". The tail end of the block stores the offsets of all of the +// restart points, and can be used to do a binary search when looking +// for a particular key. Values are stored as-is (without compression) +// immediately following the corresponding key. +// +// An entry for a particular key-value pair has the form: +// shared_bytes: varint32 +// unshared_bytes: varint32 +// value_length: varint32 +// key_delta: char[unshared_bytes] +// value: char[value_length] +// shared_bytes == 0 for restart points. +// +// The trailer of the block has the form: +// restarts: uint32[num_restarts] +// num_restarts: uint32 +// restarts[i] contains the offset within the block of the ith restart point. + +#include "table/block_builder.h" + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" + +namespace leveldb { + +BlockBuilder::BlockBuilder(const Options* options) + : options_(options), + restarts_(), + counter_(0), + finished_(false) { + assert(options->block_restart_interval >= 1); + restarts_.push_back(0); // First restart point is at offset 0 +} + +void BlockBuilder::Reset() { + buffer_.clear(); + restarts_.clear(); + restarts_.push_back(0); // First restart point is at offset 0 + counter_ = 0; + finished_ = false; + last_key_.clear(); +} + +size_t BlockBuilder::CurrentSizeEstimate() const { + return (buffer_.size() + // Raw data buffer + restarts_.size() * sizeof(uint32_t) + // Restart array + sizeof(uint32_t)); // Restart array length +} + +Slice BlockBuilder::Finish() { + // Append restart array + for (size_t i = 0; i < restarts_.size(); i++) { + PutFixed32(&buffer_, restarts_[i]); + } + PutFixed32(&buffer_, restarts_.size()); + finished_ = true; + return Slice(buffer_); +} + +void BlockBuilder::Add(const Slice& key, const Slice& value) { + Slice last_key_piece(last_key_); + assert(!finished_); + assert(counter_ <= options_->block_restart_interval); + assert(buffer_.empty() // No values yet? + || options_->comparator->Compare(key, last_key_piece) > 0); + size_t shared = 0; + if (counter_ < options_->block_restart_interval) { + // See how much sharing to do with previous string + const size_t min_length = std::min(last_key_piece.size(), key.size()); + while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { + shared++; + } + } else { + // Restart compression + restarts_.push_back(buffer_.size()); + counter_ = 0; + } + const size_t non_shared = key.size() - shared; + + // Add "" to buffer_ + PutVarint32(&buffer_, shared); + PutVarint32(&buffer_, non_shared); + PutVarint32(&buffer_, value.size()); + + // Add string delta to buffer_ followed by value + buffer_.append(key.data() + shared, non_shared); + buffer_.append(value.data(), value.size()); + + // Update state + last_key_.resize(shared); + last_key_.append(key.data() + shared, non_shared); + assert(Slice(last_key_) == key); + counter_++; +} + +} // namespace leveldb diff --git a/table/block_builder.h b/table/block_builder.h new file mode 100644 index 000000000..5b545bd1a --- /dev/null +++ b/table/block_builder.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ + +#include + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +struct Options; + +class BlockBuilder { + public: + explicit BlockBuilder(const Options* options); + + // Reset the contents as if the BlockBuilder was just constructed. + void Reset(); + + // REQUIRES: Finish() has not been callled since the last call to Reset(). + // REQUIRES: key is larger than any previously added key + void Add(const Slice& key, const Slice& value); + + // Finish building the block and return a slice that refers to the + // block contents. The returned slice will remain valid for the + // lifetime of this builder or until Reset() is called. + Slice Finish(); + + // Returns an estimate of the current (uncompressed) size of the block + // we are building. + size_t CurrentSizeEstimate() const; + + // Return true iff no entries have been added since the last Reset() + bool empty() const { + return buffer_.empty(); + } + + private: + const Options* options_; + std::string buffer_; // Destination buffer + std::vector restarts_; // Restart points + int counter_; // Number of entries emitted since restart + bool finished_; // Has Finish() been called? + std::string last_key_; + + // No copying allowed + BlockBuilder(const BlockBuilder&); + void operator=(const BlockBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/table/filter_block.cc b/table/filter_block.cc new file mode 100644 index 000000000..203e15c8b --- /dev/null +++ b/table/filter_block.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" + +namespace leveldb { + +// See doc/table_format.txt for an explanation of the filter block format. + +// Generate new filter every 2KB of data +static const size_t kFilterBaseLg = 11; +static const size_t kFilterBase = 1 << kFilterBaseLg; + +FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) + : policy_(policy) { +} + +void FilterBlockBuilder::StartBlock(uint64_t block_offset) { + uint64_t filter_index = (block_offset / kFilterBase); + assert(filter_index >= filter_offsets_.size()); + while (filter_index > filter_offsets_.size()) { + GenerateFilter(); + } +} + +void FilterBlockBuilder::AddKey(const Slice& key) { + Slice k = key; + start_.push_back(keys_.size()); + keys_.append(k.data(), k.size()); +} + +Slice FilterBlockBuilder::Finish() { + if (!start_.empty()) { + GenerateFilter(); + } + + // Append array of per-filter offsets + const uint32_t array_offset = result_.size(); + for (size_t i = 0; i < filter_offsets_.size(); i++) { + PutFixed32(&result_, filter_offsets_[i]); + } + + PutFixed32(&result_, array_offset); + result_.push_back(kFilterBaseLg); // Save encoding parameter in result + return Slice(result_); +} + +void FilterBlockBuilder::GenerateFilter() { + const size_t num_keys = start_.size(); + if (num_keys == 0) { + // Fast path if there are no keys for this filter + filter_offsets_.push_back(result_.size()); + return; + } + + // Make list of keys from flattened key structure + start_.push_back(keys_.size()); // Simplify length computation + tmp_keys_.resize(num_keys); + for (size_t i = 0; i < num_keys; i++) { + const char* base = keys_.data() + start_[i]; + size_t length = start_[i+1] - start_[i]; + tmp_keys_[i] = Slice(base, length); + } + + // Generate filter for current set of keys and append to result_. + filter_offsets_.push_back(result_.size()); + policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_); + + tmp_keys_.clear(); + keys_.clear(); + start_.clear(); +} + +FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, + const Slice& contents) + : policy_(policy), + data_(NULL), + offset_(NULL), + num_(0), + base_lg_(0) { + size_t n = contents.size(); + if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array + base_lg_ = contents[n-1]; + uint32_t last_word = DecodeFixed32(contents.data() + n - 5); + if (last_word > n - 5) return; + data_ = contents.data(); + offset_ = data_ + last_word; + num_ = (n - 5 - last_word) / 4; +} + +bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { + uint64_t index = block_offset >> base_lg_; + if (index < num_) { + uint32_t start = DecodeFixed32(offset_ + index*4); + uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); + if (start <= limit && limit <= (offset_ - data_)) { + Slice filter = Slice(data_ + start, limit - start); + return policy_->KeyMayMatch(key, filter); + } else if (start == limit) { + // Empty filters do not match any keys + return false; + } + } + return true; // Errors are treated as potential matches +} + +} diff --git a/table/filter_block.h b/table/filter_block.h new file mode 100644 index 000000000..c67d010bd --- /dev/null +++ b/table/filter_block.h @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A filter block is stored near the end of a Table file. It contains +// filters (e.g., bloom filters) for all data blocks in the table combined +// into a single filter block. + +#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ + +#include +#include +#include +#include +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +class FilterPolicy; + +// A FilterBlockBuilder is used to construct all of the filters for a +// particular Table. It generates a single string which is stored as +// a special block in the Table. +// +// The sequence of calls to FilterBlockBuilder must match the regexp: +// (StartBlock AddKey*)* Finish +class FilterBlockBuilder { + public: + explicit FilterBlockBuilder(const FilterPolicy*); + + void StartBlock(uint64_t block_offset); + void AddKey(const Slice& key); + Slice Finish(); + + private: + void GenerateFilter(); + + const FilterPolicy* policy_; + std::string keys_; // Flattened key contents + std::vector start_; // Starting index in keys_ of each key + std::string result_; // Filter data computed so far + std::vector tmp_keys_; // policy_->CreateFilter() argument + std::vector filter_offsets_; + + // No copying allowed + FilterBlockBuilder(const FilterBlockBuilder&); + void operator=(const FilterBlockBuilder&); +}; + +class FilterBlockReader { + public: + // REQUIRES: "contents" and *policy must stay live while *this is live. + FilterBlockReader(const FilterPolicy* policy, const Slice& contents); + bool KeyMayMatch(uint64_t block_offset, const Slice& key); + + private: + const FilterPolicy* policy_; + const char* data_; // Pointer to filter data (at block-start) + const char* offset_; // Pointer to beginning of offset array (at block-end) + size_t num_; // Number of entries in offset array + size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) +}; + +} + +#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/table/filter_block_test.cc b/table/filter_block_test.cc new file mode 100644 index 000000000..3a2a07cf5 --- /dev/null +++ b/table/filter_block_test.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// For testing: emit an array with one hash value per key +class TestHashFilter : public FilterPolicy { + public: + virtual const char* Name() const { + return "TestHashFilter"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + for (int i = 0; i < n; i++) { + uint32_t h = Hash(keys[i].data(), keys[i].size(), 1); + PutFixed32(dst, h); + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + uint32_t h = Hash(key.data(), key.size(), 1); + for (int i = 0; i + 4 <= filter.size(); i += 4) { + if (h == DecodeFixed32(filter.data() + i)) { + return true; + } + } + return false; + } +}; + +class FilterBlockTest { + public: + TestHashFilter policy_; +}; + +TEST(FilterBlockTest, EmptyBuilder) { + FilterBlockBuilder builder(&policy_); + Slice block = builder.Finish(); + ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block)); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100000, "foo")); +} + +TEST(FilterBlockTest, SingleChunk) { + FilterBlockBuilder builder(&policy_); + builder.StartBlock(100); + builder.AddKey("foo"); + builder.AddKey("bar"); + builder.AddKey("box"); + builder.StartBlock(200); + builder.AddKey("box"); + builder.StartBlock(300); + builder.AddKey("hello"); + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100, "bar")); + ASSERT_TRUE(reader.KeyMayMatch(100, "box")); + ASSERT_TRUE(reader.KeyMayMatch(100, "hello")); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "missing")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "other")); +} + +TEST(FilterBlockTest, MultiChunk) { + FilterBlockBuilder builder(&policy_); + + // First filter + builder.StartBlock(0); + builder.AddKey("foo"); + builder.StartBlock(2000); + builder.AddKey("bar"); + + // Second filter + builder.StartBlock(3100); + builder.AddKey("box"); + + // Third filter is empty + + // Last filter + builder.StartBlock(9000); + builder.AddKey("box"); + builder.AddKey("hello"); + + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + + // Check first filter + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(2000, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "hello")); + + // Check second filter + ASSERT_TRUE(reader.KeyMayMatch(3100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "hello")); + + // Check third filter (empty) + ASSERT_TRUE(! reader.KeyMayMatch(4100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "hello")); + + // Check last filter + ASSERT_TRUE(reader.KeyMayMatch(9000, "box")); + ASSERT_TRUE(reader.KeyMayMatch(9000, "hello")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "bar")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/table/format.cc b/table/format.cc new file mode 100644 index 000000000..cda1decdf --- /dev/null +++ b/table/format.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/format.h" + +#include "leveldb/env.h" +#include "port/port.h" +#include "table/block.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +void BlockHandle::EncodeTo(std::string* dst) const { + // Sanity check that all fields have been set + assert(offset_ != ~static_cast(0)); + assert(size_ != ~static_cast(0)); + PutVarint64(dst, offset_); + PutVarint64(dst, size_); +} + +Status BlockHandle::DecodeFrom(Slice* input) { + if (GetVarint64(input, &offset_) && + GetVarint64(input, &size_)) { + return Status::OK(); + } else { + return Status::Corruption("bad block handle"); + } +} + +void Footer::EncodeTo(std::string* dst) const { +#ifndef NDEBUG + const size_t original_size = dst->size(); +#endif + metaindex_handle_.EncodeTo(dst); + index_handle_.EncodeTo(dst); + dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding + PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); + PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); + assert(dst->size() == original_size + kEncodedLength); +} + +Status Footer::DecodeFrom(Slice* input) { + const char* magic_ptr = input->data() + kEncodedLength - 8; + const uint32_t magic_lo = DecodeFixed32(magic_ptr); + const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); + const uint64_t magic = ((static_cast(magic_hi) << 32) | + (static_cast(magic_lo))); + if (magic != kTableMagicNumber) { + return Status::InvalidArgument("not an sstable (bad magic number)"); + } + + Status result = metaindex_handle_.DecodeFrom(input); + if (result.ok()) { + result = index_handle_.DecodeFrom(input); + } + if (result.ok()) { + // We skip over any leftover data (just padding for now) in "input" + const char* end = magic_ptr + 8; + *input = Slice(end, input->data() + input->size() - end); + } + return result; +} + +Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result) { + result->data = Slice(); + result->cachable = false; + result->heap_allocated = false; + + // Read the block contents as well as the type/crc footer. + // See table_builder.cc for the code that built this structure. + size_t n = static_cast(handle.size()); + char* buf = new char[n + kBlockTrailerSize]; + Slice contents; + Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); + if (!s.ok()) { + delete[] buf; + return s; + } + if (contents.size() != n + kBlockTrailerSize) { + delete[] buf; + return Status::Corruption("truncated block read"); + } + + // Check the crc of the type and the block contents + const char* data = contents.data(); // Pointer to where Read put the data + if (options.verify_checksums) { + const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); + const uint32_t actual = crc32c::Value(data, n + 1); + if (actual != crc) { + delete[] buf; + s = Status::Corruption("block checksum mismatch"); + return s; + } + } + + switch (data[n]) { + case kNoCompression: + if (data != buf) { + // File implementation gave us pointer to some other data. + // Use it directly under the assumption that it will be live + // while the file is open. + delete[] buf; + result->data = Slice(data, n); + result->heap_allocated = false; + result->cachable = false; // Do not double-cache + } else { + result->data = Slice(buf, n); + result->heap_allocated = true; + result->cachable = true; + } + + // Ok + break; + case kSnappyCompression: { + size_t ulength = 0; + if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { + delete[] buf; + return Status::Corruption("corrupted compressed block contents"); + } + char* ubuf = new char[ulength]; + if (!port::Snappy_Uncompress(data, n, ubuf)) { + delete[] buf; + delete[] ubuf; + return Status::Corruption("corrupted compressed block contents"); + } + delete[] buf; + result->data = Slice(ubuf, ulength); + result->heap_allocated = true; + result->cachable = true; + break; + } + default: + delete[] buf; + return Status::Corruption("bad block type"); + } + + return Status::OK(); +} + +} // namespace leveldb diff --git a/table/format.h b/table/format.h new file mode 100644 index 000000000..6c0b80c01 --- /dev/null +++ b/table/format.h @@ -0,0 +1,108 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_ +#define STORAGE_LEVELDB_TABLE_FORMAT_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "leveldb/table_builder.h" + +namespace leveldb { + +class Block; +class RandomAccessFile; +struct ReadOptions; + +// BlockHandle is a pointer to the extent of a file that stores a data +// block or a meta block. +class BlockHandle { + public: + BlockHandle(); + + // The offset of the block in the file. + uint64_t offset() const { return offset_; } + void set_offset(uint64_t offset) { offset_ = offset; } + + // The size of the stored block + uint64_t size() const { return size_; } + void set_size(uint64_t size) { size_ = size; } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Maximum encoding length of a BlockHandle + enum { kMaxEncodedLength = 10 + 10 }; + + private: + uint64_t offset_; + uint64_t size_; +}; + +// Footer encapsulates the fixed information stored at the tail +// end of every table file. +class Footer { + public: + Footer() { } + + // The block handle for the metaindex block of the table + const BlockHandle& metaindex_handle() const { return metaindex_handle_; } + void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } + + // The block handle for the index block of the table + const BlockHandle& index_handle() const { + return index_handle_; + } + void set_index_handle(const BlockHandle& h) { + index_handle_ = h; + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Encoded length of a Footer. Note that the serialization of a + // Footer will always occupy exactly this many bytes. It consists + // of two block handles and a magic number. + enum { + kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8 + }; + + private: + BlockHandle metaindex_handle_; + BlockHandle index_handle_; +}; + +// kTableMagicNumber was picked by running +// echo http://code.google.com/p/leveldb/ | sha1sum +// and taking the leading 64 bits. +static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; + +// 1-byte type + 32-bit crc +static const size_t kBlockTrailerSize = 5; + +struct BlockContents { + Slice data; // Actual contents of data + bool cachable; // True iff data can be cached + bool heap_allocated; // True iff caller should delete[] data.data() +}; + +// Read the block identified by "handle" from "file". On failure +// return non-OK. On success fill *result and return OK. +extern Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result); + +// Implementation details follow. Clients should ignore, + +inline BlockHandle::BlockHandle() + : offset_(~static_cast(0)), + size_(~static_cast(0)) { +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/table/iterator.cc b/table/iterator.cc new file mode 100644 index 000000000..3d1c87fde --- /dev/null +++ b/table/iterator.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/iterator.h" + +namespace leveldb { + +Iterator::Iterator() { + cleanup_.function = NULL; + cleanup_.next = NULL; +} + +Iterator::~Iterator() { + if (cleanup_.function != NULL) { + (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2); + for (Cleanup* c = cleanup_.next; c != NULL; ) { + (*c->function)(c->arg1, c->arg2); + Cleanup* next = c->next; + delete c; + c = next; + } + } +} + +void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { + assert(func != NULL); + Cleanup* c; + if (cleanup_.function == NULL) { + c = &cleanup_; + } else { + c = new Cleanup; + c->next = cleanup_.next; + cleanup_.next = c; + } + c->function = func; + c->arg1 = arg1; + c->arg2 = arg2; +} + +namespace { +class EmptyIterator : public Iterator { + public: + EmptyIterator(const Status& s) : status_(s) { } + virtual bool Valid() const { return false; } + virtual void Seek(const Slice& target) { } + virtual void SeekToFirst() { } + virtual void SeekToLast() { } + virtual void Next() { assert(false); } + virtual void Prev() { assert(false); } + Slice key() const { assert(false); return Slice(); } + Slice value() const { assert(false); return Slice(); } + virtual Status status() const { return status_; } + private: + Status status_; +}; +} // namespace + +Iterator* NewEmptyIterator() { + return new EmptyIterator(Status::OK()); +} + +Iterator* NewErrorIterator(const Status& status) { + return new EmptyIterator(status); +} + +} // namespace leveldb diff --git a/table/iterator_wrapper.h b/table/iterator_wrapper.h new file mode 100644 index 000000000..9e16b3dbe --- /dev/null +++ b/table/iterator_wrapper.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ +#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ + +namespace leveldb { + +// A internal wrapper class with an interface similar to Iterator that +// caches the valid() and key() results for an underlying iterator. +// This can help avoid virtual function calls and also gives better +// cache locality. +class IteratorWrapper { + public: + IteratorWrapper(): iter_(NULL), valid_(false) { } + explicit IteratorWrapper(Iterator* iter): iter_(NULL) { + Set(iter); + } + ~IteratorWrapper() { delete iter_; } + Iterator* iter() const { return iter_; } + + // Takes ownership of "iter" and will delete it when destroyed, or + // when Set() is invoked again. + void Set(Iterator* iter) { + delete iter_; + iter_ = iter; + if (iter_ == NULL) { + valid_ = false; + } else { + Update(); + } + } + + + // Iterator interface methods + bool Valid() const { return valid_; } + Slice key() const { assert(Valid()); return key_; } + Slice value() const { assert(Valid()); return iter_->value(); } + // Methods below require iter() != NULL + Status status() const { assert(iter_); return iter_->status(); } + void Next() { assert(iter_); iter_->Next(); Update(); } + void Prev() { assert(iter_); iter_->Prev(); Update(); } + void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } + void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } + void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } + + private: + void Update() { + valid_ = iter_->Valid(); + if (valid_) { + key_ = iter_->key(); + } + } + + Iterator* iter_; + bool valid_; + Slice key_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/table/merger.cc b/table/merger.cc new file mode 100644 index 000000000..2dde4dc21 --- /dev/null +++ b/table/merger.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/merger.h" + +#include "leveldb/comparator.h" +#include "leveldb/iterator.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { +class MergingIterator : public Iterator { + public: + MergingIterator(const Comparator* comparator, Iterator** children, int n) + : comparator_(comparator), + children_(new IteratorWrapper[n]), + n_(n), + current_(NULL), + direction_(kForward) { + for (int i = 0; i < n; i++) { + children_[i].Set(children[i]); + } + } + + virtual ~MergingIterator() { + delete[] children_; + } + + virtual bool Valid() const { + return (current_ != NULL); + } + + virtual void SeekToFirst() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToFirst(); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void SeekToLast() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToLast(); + } + FindLargest(); + direction_ = kReverse; + } + + virtual void Seek(const Slice& target) { + for (int i = 0; i < n_; i++) { + children_[i].Seek(target); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void Next() { + assert(Valid()); + + // Ensure that all children are positioned after key(). + // If we are moving in the forward direction, it is already + // true for all of the non-current_ children since current_ is + // the smallest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kForward) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid() && + comparator_->Compare(key(), child->key()) == 0) { + child->Next(); + } + } + } + direction_ = kForward; + } + + current_->Next(); + FindSmallest(); + } + + virtual void Prev() { + assert(Valid()); + + // Ensure that all children are positioned before key(). + // If we are moving in the reverse direction, it is already + // true for all of the non-current_ children since current_ is + // the largest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kReverse) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid()) { + // Child is at first entry >= key(). Step back one to be < key() + child->Prev(); + } else { + // Child has no entries >= key(). Position at last entry. + child->SeekToLast(); + } + } + } + direction_ = kReverse; + } + + current_->Prev(); + FindLargest(); + } + + virtual Slice key() const { + assert(Valid()); + return current_->key(); + } + + virtual Slice value() const { + assert(Valid()); + return current_->value(); + } + + virtual Status status() const { + Status status; + for (int i = 0; i < n_; i++) { + status = children_[i].status(); + if (!status.ok()) { + break; + } + } + return status; + } + + private: + void FindSmallest(); + void FindLargest(); + + // We might want to use a heap in case there are lots of children. + // For now we use a simple array since we expect a very small number + // of children in leveldb. + const Comparator* comparator_; + IteratorWrapper* children_; + int n_; + IteratorWrapper* current_; + + // Which direction is the iterator moving? + enum Direction { + kForward, + kReverse + }; + Direction direction_; +}; + +void MergingIterator::FindSmallest() { + IteratorWrapper* smallest = NULL; + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (smallest == NULL) { + smallest = child; + } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { + smallest = child; + } + } + } + current_ = smallest; +} + +void MergingIterator::FindLargest() { + IteratorWrapper* largest = NULL; + for (int i = n_-1; i >= 0; i--) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (largest == NULL) { + largest = child; + } else if (comparator_->Compare(child->key(), largest->key()) > 0) { + largest = child; + } + } + } + current_ = largest; +} +} // namespace + +Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) { + assert(n >= 0); + if (n == 0) { + return NewEmptyIterator(); + } else if (n == 1) { + return list[0]; + } else { + return new MergingIterator(cmp, list, n); + } +} + +} // namespace leveldb diff --git a/table/merger.h b/table/merger.h new file mode 100644 index 000000000..91ddd80fa --- /dev/null +++ b/table/merger.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_ +#define STORAGE_LEVELDB_TABLE_MERGER_H_ + +namespace leveldb { + +class Comparator; +class Iterator; + +// Return an iterator that provided the union of the data in +// children[0,n-1]. Takes ownership of the child iterators and +// will delete them when the result iterator is deleted. +// +// The result does no duplicate suppression. I.e., if a particular +// key is present in K child iterators, it will be yielded K times. +// +// REQUIRES: n >= 0 +extern Iterator* NewMergingIterator( + const Comparator* comparator, Iterator** children, int n); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/table/table.cc b/table/table.cc new file mode 100644 index 000000000..dbd6d3a1b --- /dev/null +++ b/table/table.cc @@ -0,0 +1,276 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" + +namespace leveldb { + +struct Table::Rep { + ~Rep() { + delete filter; + delete [] filter_data; + delete index_block; + } + + Options options; + Status status; + RandomAccessFile* file; + uint64_t cache_id; + FilterBlockReader* filter; + const char* filter_data; + + BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer + Block* index_block; +}; + +Status Table::Open(const Options& options, + RandomAccessFile* file, + uint64_t size, + Table** table) { + *table = NULL; + if (size < Footer::kEncodedLength) { + return Status::InvalidArgument("file is too short to be an sstable"); + } + + char footer_space[Footer::kEncodedLength]; + Slice footer_input; + Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, + &footer_input, footer_space); + if (!s.ok()) return s; + + Footer footer; + s = footer.DecodeFrom(&footer_input); + if (!s.ok()) return s; + + // Read the index block + BlockContents contents; + Block* index_block = NULL; + if (s.ok()) { + s = ReadBlock(file, ReadOptions(), footer.index_handle(), &contents); + if (s.ok()) { + index_block = new Block(contents); + } + } + + if (s.ok()) { + // We've successfully read the footer and the index block: we're + // ready to serve requests. + Rep* rep = new Table::Rep; + rep->options = options; + rep->file = file; + rep->metaindex_handle = footer.metaindex_handle(); + rep->index_block = index_block; + rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); + rep->filter_data = NULL; + rep->filter = NULL; + *table = new Table(rep); + (*table)->ReadMeta(footer); + } else { + if (index_block) delete index_block; + } + + return s; +} + +void Table::ReadMeta(const Footer& footer) { + if (rep_->options.filter_policy == NULL) { + return; // Do not need any metadata + } + + // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates + // it is an empty block. + ReadOptions opt; + BlockContents contents; + if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { + // Do not propagate errors since meta info is not needed for operation + return; + } + Block* meta = new Block(contents); + + Iterator* iter = meta->NewIterator(BytewiseComparator()); + std::string key = "filter."; + key.append(rep_->options.filter_policy->Name()); + iter->Seek(key); + if (iter->Valid() && iter->key() == Slice(key)) { + ReadFilter(iter->value()); + } + delete iter; + delete meta; +} + +void Table::ReadFilter(const Slice& filter_handle_value) { + Slice v = filter_handle_value; + BlockHandle filter_handle; + if (!filter_handle.DecodeFrom(&v).ok()) { + return; + } + + // We might want to unify with ReadBlock() if we start + // requiring checksum verification in Table::Open. + ReadOptions opt; + BlockContents block; + if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { + return; + } + if (block.heap_allocated) { + rep_->filter_data = block.data.data(); // Will need to delete later + } + rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); +} + +Table::~Table() { + delete rep_; +} + +static void DeleteBlock(void* arg, void* ignored) { + delete reinterpret_cast(arg); +} + +static void DeleteCachedBlock(const Slice& key, void* value) { + Block* block = reinterpret_cast(value); + delete block; +} + +static void ReleaseBlock(void* arg, void* h) { + Cache* cache = reinterpret_cast(arg); + Cache::Handle* handle = reinterpret_cast(h); + cache->Release(handle); +} + +// Convert an index iterator value (i.e., an encoded BlockHandle) +// into an iterator over the contents of the corresponding block. +Iterator* Table::BlockReader(void* arg, + const ReadOptions& options, + const Slice& index_value) { + Table* table = reinterpret_cast(arg); + Cache* block_cache = table->rep_->options.block_cache; + Block* block = NULL; + Cache::Handle* cache_handle = NULL; + + BlockHandle handle; + Slice input = index_value; + Status s = handle.DecodeFrom(&input); + // We intentionally allow extra stuff in index_value so that we + // can add more features in the future. + + if (s.ok()) { + BlockContents contents; + if (block_cache != NULL) { + char cache_key_buffer[16]; + EncodeFixed64(cache_key_buffer, table->rep_->cache_id); + EncodeFixed64(cache_key_buffer+8, handle.offset()); + Slice key(cache_key_buffer, sizeof(cache_key_buffer)); + cache_handle = block_cache->Lookup(key); + if (cache_handle != NULL) { + block = reinterpret_cast(block_cache->Value(cache_handle)); + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + if (contents.cachable && options.fill_cache) { + cache_handle = block_cache->Insert( + key, block, block->size(), &DeleteCachedBlock); + } + } + } + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + } + } + } + + Iterator* iter; + if (block != NULL) { + iter = block->NewIterator(table->rep_->options.comparator); + if (cache_handle == NULL) { + iter->RegisterCleanup(&DeleteBlock, block, NULL); + } else { + iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); + } + } else { + iter = NewErrorIterator(s); + } + return iter; +} + +Iterator* Table::NewIterator(const ReadOptions& options) const { + return NewTwoLevelIterator( + rep_->index_block->NewIterator(rep_->options.comparator), + &Table::BlockReader, const_cast(this), options); +} + +Status Table::InternalGet(const ReadOptions& options, const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Status s; + Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); + iiter->Seek(k); + if (iiter->Valid()) { + Slice handle_value = iiter->value(); + FilterBlockReader* filter = rep_->filter; + BlockHandle handle; + if (filter != NULL && + handle.DecodeFrom(&handle_value).ok() && + !filter->KeyMayMatch(handle.offset(), k)) { + // Not found + } else { + Slice handle = iiter->value(); + Iterator* block_iter = BlockReader(this, options, iiter->value()); + block_iter->Seek(k); + if (block_iter->Valid()) { + (*saver)(arg, block_iter->key(), block_iter->value()); + } + s = block_iter->status(); + delete block_iter; + } + } + if (s.ok()) { + s = iiter->status(); + } + delete iiter; + return s; +} + + +uint64_t Table::ApproximateOffsetOf(const Slice& key) const { + Iterator* index_iter = + rep_->index_block->NewIterator(rep_->options.comparator); + index_iter->Seek(key); + uint64_t result; + if (index_iter->Valid()) { + BlockHandle handle; + Slice input = index_iter->value(); + Status s = handle.DecodeFrom(&input); + if (s.ok()) { + result = handle.offset(); + } else { + // Strange: we can't decode the block handle in the index block. + // We'll just return the offset of the metaindex block, which is + // close to the whole file size for this case. + result = rep_->metaindex_handle.offset(); + } + } else { + // key is past the last key in the file. Approximate the offset + // by returning the offset of the metaindex block (which is + // right near the end of the file). + result = rep_->metaindex_handle.offset(); + } + delete index_iter; + return result; +} + +} // namespace leveldb diff --git a/table/table_builder.cc b/table/table_builder.cc new file mode 100644 index 000000000..62002c84f --- /dev/null +++ b/table/table_builder.cc @@ -0,0 +1,270 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table_builder.h" + +#include +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block_builder.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +struct TableBuilder::Rep { + Options options; + Options index_block_options; + WritableFile* file; + uint64_t offset; + Status status; + BlockBuilder data_block; + BlockBuilder index_block; + std::string last_key; + int64_t num_entries; + bool closed; // Either Finish() or Abandon() has been called. + FilterBlockBuilder* filter_block; + + // We do not emit the index entry for a block until we have seen the + // first key for the next data block. This allows us to use shorter + // keys in the index block. For example, consider a block boundary + // between the keys "the quick brown fox" and "the who". We can use + // "the r" as the key for the index block entry since it is >= all + // entries in the first block and < all entries in subsequent + // blocks. + // + // Invariant: r->pending_index_entry is true only if data_block is empty. + bool pending_index_entry; + BlockHandle pending_handle; // Handle to add to index block + + std::string compressed_output; + + Rep(const Options& opt, WritableFile* f) + : options(opt), + index_block_options(opt), + file(f), + offset(0), + data_block(&options), + index_block(&index_block_options), + num_entries(0), + closed(false), + filter_block(opt.filter_policy == NULL ? NULL + : new FilterBlockBuilder(opt.filter_policy)), + pending_index_entry(false) { + index_block_options.block_restart_interval = 1; + } +}; + +TableBuilder::TableBuilder(const Options& options, WritableFile* file) + : rep_(new Rep(options, file)) { + if (rep_->filter_block != NULL) { + rep_->filter_block->StartBlock(0); + } +} + +TableBuilder::~TableBuilder() { + assert(rep_->closed); // Catch errors where caller forgot to call Finish() + delete rep_->filter_block; + delete rep_; +} + +Status TableBuilder::ChangeOptions(const Options& options) { + // Note: if more fields are added to Options, update + // this function to catch changes that should not be allowed to + // change in the middle of building a Table. + if (options.comparator != rep_->options.comparator) { + return Status::InvalidArgument("changing comparator while building table"); + } + + // Note that any live BlockBuilders point to rep_->options and therefore + // will automatically pick up the updated options. + rep_->options = options; + rep_->index_block_options = options; + rep_->index_block_options.block_restart_interval = 1; + return Status::OK(); +} + +void TableBuilder::Add(const Slice& key, const Slice& value) { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->num_entries > 0) { + assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); + } + + if (r->pending_index_entry) { + assert(r->data_block.empty()); + r->options.comparator->FindShortestSeparator(&r->last_key, key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + + if (r->filter_block != NULL) { + r->filter_block->AddKey(key); + } + + r->last_key.assign(key.data(), key.size()); + r->num_entries++; + r->data_block.Add(key, value); + + const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); + if (estimated_block_size >= r->options.block_size) { + Flush(); + } +} + +void TableBuilder::Flush() { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->data_block.empty()) return; + assert(!r->pending_index_entry); + WriteBlock(&r->data_block, &r->pending_handle); + if (ok()) { + r->pending_index_entry = true; + r->status = r->file->Flush(); + } + if (r->filter_block != NULL) { + r->filter_block->StartBlock(r->offset); + } +} + +void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { + // File format contains a sequence of blocks where each block has: + // block_data: uint8[n] + // type: uint8 + // crc: uint32 + assert(ok()); + Rep* r = rep_; + Slice raw = block->Finish(); + + Slice block_contents; + CompressionType type = r->options.compression; + // TODO(postrelease): Support more compression options: zlib? + switch (type) { + case kNoCompression: + block_contents = raw; + break; + + case kSnappyCompression: { + std::string* compressed = &r->compressed_output; + if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && + compressed->size() < raw.size() - (raw.size() / 8u)) { + block_contents = *compressed; + } else { + // Snappy not supported, or compressed less than 12.5%, so just + // store uncompressed form + block_contents = raw; + type = kNoCompression; + } + break; + } + } + WriteRawBlock(block_contents, type, handle); + r->compressed_output.clear(); + block->Reset(); +} + +void TableBuilder::WriteRawBlock(const Slice& block_contents, + CompressionType type, + BlockHandle* handle) { + Rep* r = rep_; + handle->set_offset(r->offset); + handle->set_size(block_contents.size()); + r->status = r->file->Append(block_contents); + if (r->status.ok()) { + char trailer[kBlockTrailerSize]; + trailer[0] = type; + uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); + crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type + EncodeFixed32(trailer+1, crc32c::Mask(crc)); + r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); + if (r->status.ok()) { + r->offset += block_contents.size() + kBlockTrailerSize; + } + } +} + +Status TableBuilder::status() const { + return rep_->status; +} + +Status TableBuilder::Finish() { + Rep* r = rep_; + Flush(); + assert(!r->closed); + r->closed = true; + + BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; + + // Write filter block + if (ok() && r->filter_block != NULL) { + WriteRawBlock(r->filter_block->Finish(), kNoCompression, + &filter_block_handle); + } + + // Write metaindex block + if (ok()) { + BlockBuilder meta_index_block(&r->options); + if (r->filter_block != NULL) { + // Add mapping from "filter.Name" to location of filter data + std::string key = "filter."; + key.append(r->options.filter_policy->Name()); + std::string handle_encoding; + filter_block_handle.EncodeTo(&handle_encoding); + meta_index_block.Add(key, handle_encoding); + } + + // TODO(postrelease): Add stats and other meta blocks + WriteBlock(&meta_index_block, &metaindex_block_handle); + } + + // Write index block + if (ok()) { + if (r->pending_index_entry) { + r->options.comparator->FindShortSuccessor(&r->last_key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + WriteBlock(&r->index_block, &index_block_handle); + } + + // Write footer + if (ok()) { + Footer footer; + footer.set_metaindex_handle(metaindex_block_handle); + footer.set_index_handle(index_block_handle); + std::string footer_encoding; + footer.EncodeTo(&footer_encoding); + r->status = r->file->Append(footer_encoding); + if (r->status.ok()) { + r->offset += footer_encoding.size(); + } + } + return r->status; +} + +void TableBuilder::Abandon() { + Rep* r = rep_; + assert(!r->closed); + r->closed = true; +} + +uint64_t TableBuilder::NumEntries() const { + return rep_->num_entries; +} + +uint64_t TableBuilder::FileSize() const { + return rep_->offset; +} + +} // namespace leveldb diff --git a/table/table_test.cc b/table/table_test.cc new file mode 100644 index 000000000..57cea2533 --- /dev/null +++ b/table/table_test.cc @@ -0,0 +1,838 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include +#include +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/table_builder.h" +#include "table/block.h" +#include "table/block_builder.h" +#include "table/format.h" +#include "util/random.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// Return reverse of "key". +// Used to test non-lexicographic comparators. +static std::string Reverse(const Slice& key) { + std::string str(key.ToString()); + std::string rev(""); + for (std::string::reverse_iterator rit = str.rbegin(); + rit != str.rend(); ++rit) { + rev.push_back(*rit); + } + return rev; +} + +namespace { +class ReverseKeyComparator : public Comparator { + public: + virtual const char* Name() const { + return "leveldb.ReverseBytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(Reverse(a), Reverse(b)); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + std::string s = Reverse(*start); + std::string l = Reverse(limit); + BytewiseComparator()->FindShortestSeparator(&s, l); + *start = Reverse(s); + } + + virtual void FindShortSuccessor(std::string* key) const { + std::string s = Reverse(*key); + BytewiseComparator()->FindShortSuccessor(&s); + *key = Reverse(s); + } +}; +} // namespace +static ReverseKeyComparator reverse_key_comparator; + +static void Increment(const Comparator* cmp, std::string* key) { + if (cmp == BytewiseComparator()) { + key->push_back('\0'); + } else { + assert(cmp == &reverse_key_comparator); + std::string rev = Reverse(*key); + rev.push_back('\0'); + *key = Reverse(rev); + } +} + +// An STL comparator that uses a Comparator +namespace { +struct STLLessThan { + const Comparator* cmp; + + STLLessThan() : cmp(BytewiseComparator()) { } + STLLessThan(const Comparator* c) : cmp(c) { } + bool operator()(const std::string& a, const std::string& b) const { + return cmp->Compare(Slice(a), Slice(b)) < 0; + } +}; +} // namespace + +class StringSink: public WritableFile { + public: + ~StringSink() { } + + const std::string& contents() const { return contents_; } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + virtual Status Append(const Slice& data) { + contents_.append(data.data(), data.size()); + return Status::OK(); + } + + private: + std::string contents_; +}; + + +class StringSource: public RandomAccessFile { + public: + StringSource(const Slice& contents) + : contents_(contents.data(), contents.size()) { + } + + virtual ~StringSource() { } + + uint64_t Size() const { return contents_.size(); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + if (offset > contents_.size()) { + return Status::InvalidArgument("invalid Read offset"); + } + if (offset + n > contents_.size()) { + n = contents_.size() - offset; + } + memcpy(scratch, &contents_[offset], n); + *result = Slice(scratch, n); + return Status::OK(); + } + + private: + std::string contents_; +}; + +typedef std::map KVMap; + +// Helper class for tests to unify the interface between +// BlockBuilder/TableBuilder and Block/Table. +class Constructor { + public: + explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { } + virtual ~Constructor() { } + + void Add(const std::string& key, const Slice& value) { + data_[key] = value.ToString(); + } + + // Finish constructing the data structure with all the keys that have + // been added so far. Returns the keys in sorted order in "*keys" + // and stores the key/value pairs in "*kvmap" + void Finish(const Options& options, + std::vector* keys, + KVMap* kvmap) { + *kvmap = data_; + keys->clear(); + for (KVMap::const_iterator it = data_.begin(); + it != data_.end(); + ++it) { + keys->push_back(it->first); + } + data_.clear(); + Status s = FinishImpl(options, *kvmap); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + // Construct the data structure from the data in "data" + virtual Status FinishImpl(const Options& options, const KVMap& data) = 0; + + virtual Iterator* NewIterator() const = 0; + + virtual const KVMap& data() { return data_; } + + virtual DB* db() const { return NULL; } // Overridden in DBConstructor + + private: + KVMap data_; +}; + +class BlockConstructor: public Constructor { + public: + explicit BlockConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp), + block_(NULL) { } + ~BlockConstructor() { + delete block_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete block_; + block_ = NULL; + BlockBuilder builder(&options); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + } + // Open the block + data_ = builder.Finish().ToString(); + BlockContents contents; + contents.data = data_; + contents.cachable = false; + contents.heap_allocated = false; + block_ = new Block(contents); + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return block_->NewIterator(comparator_); + } + + private: + const Comparator* comparator_; + std::string data_; + Block* block_; + + BlockConstructor(); +}; + +class TableConstructor: public Constructor { + public: + TableConstructor(const Comparator* cmp) + : Constructor(cmp), + source_(NULL), table_(NULL) { + } + ~TableConstructor() { + Reset(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + Reset(); + StringSink sink; + TableBuilder builder(options, &sink); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + ASSERT_TRUE(builder.status().ok()); + } + Status s = builder.Finish(); + ASSERT_TRUE(s.ok()) << s.ToString(); + + ASSERT_EQ(sink.contents().size(), builder.FileSize()); + + // Open the table + source_ = new StringSource(sink.contents()); + Options table_options; + table_options.comparator = options.comparator; + return Table::Open(table_options, source_, sink.contents().size(), &table_); + } + + virtual Iterator* NewIterator() const { + return table_->NewIterator(ReadOptions()); + } + + uint64_t ApproximateOffsetOf(const Slice& key) const { + return table_->ApproximateOffsetOf(key); + } + + private: + void Reset() { + delete table_; + delete source_; + table_ = NULL; + source_ = NULL; + } + + StringSource* source_; + Table* table_; + + TableConstructor(); +}; + +// A helper class that converts internal format keys into user keys +class KeyConvertingIterator: public Iterator { + public: + explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { } + virtual ~KeyConvertingIterator() { delete iter_; } + virtual bool Valid() const { return iter_->Valid(); } + virtual void Seek(const Slice& target) { + ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue); + std::string encoded; + AppendInternalKey(&encoded, ikey); + iter_->Seek(encoded); + } + virtual void SeekToFirst() { iter_->SeekToFirst(); } + virtual void SeekToLast() { iter_->SeekToLast(); } + virtual void Next() { iter_->Next(); } + virtual void Prev() { iter_->Prev(); } + + virtual Slice key() const { + assert(Valid()); + ParsedInternalKey key; + if (!ParseInternalKey(iter_->key(), &key)) { + status_ = Status::Corruption("malformed internal key"); + return Slice("corrupted key"); + } + return key.user_key; + } + + virtual Slice value() const { return iter_->value(); } + virtual Status status() const { + return status_.ok() ? iter_->status() : status_; + } + + private: + mutable Status status_; + Iterator* iter_; + + // No copying allowed + KeyConvertingIterator(const KeyConvertingIterator&); + void operator=(const KeyConvertingIterator&); +}; + +class MemTableConstructor: public Constructor { + public: + explicit MemTableConstructor(const Comparator* cmp) + : Constructor(cmp), + internal_comparator_(cmp) { + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + } + ~MemTableConstructor() { + memtable_->Unref(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + memtable_->Unref(); + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + int seq = 1; + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + memtable_->Add(seq, kTypeValue, it->first, it->second); + seq++; + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return new KeyConvertingIterator(memtable_->NewIterator()); + } + + private: + InternalKeyComparator internal_comparator_; + MemTable* memtable_; +}; + +class DBConstructor: public Constructor { + public: + explicit DBConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp) { + db_ = NULL; + NewDB(); + } + ~DBConstructor() { + delete db_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete db_; + db_ = NULL; + NewDB(); + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + WriteBatch batch; + batch.Put(it->first, it->second); + ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok()); + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return db_->NewIterator(ReadOptions()); + } + + virtual DB* db() const { return db_; } + + private: + void NewDB() { + std::string name = test::TmpDir() + "/table_testdb"; + + Options options; + options.comparator = comparator_; + Status status = DestroyDB(name, options); + ASSERT_TRUE(status.ok()) << status.ToString(); + + options.create_if_missing = true; + options.error_if_exists = true; + options.write_buffer_size = 10000; // Something small to force merging + status = DB::Open(options, name, &db_); + ASSERT_TRUE(status.ok()) << status.ToString(); + } + + const Comparator* comparator_; + DB* db_; +}; + +enum TestType { + TABLE_TEST, + BLOCK_TEST, + MEMTABLE_TEST, + DB_TEST +}; + +struct TestArgs { + TestType type; + bool reverse_compare; + int restart_interval; +}; + +static const TestArgs kTestArgList[] = { + { TABLE_TEST, false, 16 }, + { TABLE_TEST, false, 1 }, + { TABLE_TEST, false, 1024 }, + { TABLE_TEST, true, 16 }, + { TABLE_TEST, true, 1 }, + { TABLE_TEST, true, 1024 }, + + { BLOCK_TEST, false, 16 }, + { BLOCK_TEST, false, 1 }, + { BLOCK_TEST, false, 1024 }, + { BLOCK_TEST, true, 16 }, + { BLOCK_TEST, true, 1 }, + { BLOCK_TEST, true, 1024 }, + + // Restart interval does not matter for memtables + { MEMTABLE_TEST, false, 16 }, + { MEMTABLE_TEST, true, 16 }, + + // Do not bother with restart interval variations for DB + { DB_TEST, false, 16 }, + { DB_TEST, true, 16 }, +}; +static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]); + +class Harness { + public: + Harness() : constructor_(NULL) { } + + void Init(const TestArgs& args) { + delete constructor_; + constructor_ = NULL; + options_ = Options(); + + options_.block_restart_interval = args.restart_interval; + // Use shorter block size for tests to exercise block boundary + // conditions more. + options_.block_size = 256; + if (args.reverse_compare) { + options_.comparator = &reverse_key_comparator; + } + switch (args.type) { + case TABLE_TEST: + constructor_ = new TableConstructor(options_.comparator); + break; + case BLOCK_TEST: + constructor_ = new BlockConstructor(options_.comparator); + break; + case MEMTABLE_TEST: + constructor_ = new MemTableConstructor(options_.comparator); + break; + case DB_TEST: + constructor_ = new DBConstructor(options_.comparator); + break; + } + } + + ~Harness() { + delete constructor_; + } + + void Add(const std::string& key, const std::string& value) { + constructor_->Add(key, value); + } + + void Test(Random* rnd) { + std::vector keys; + KVMap data; + constructor_->Finish(options_, &keys, &data); + + TestForwardScan(keys, data); + TestBackwardScan(keys, data); + TestRandomAccess(rnd, keys, data); + } + + void TestForwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToFirst(); + for (KVMap::const_iterator model_iter = data.begin(); + model_iter != data.end(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Next(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestBackwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + for (KVMap::const_reverse_iterator model_iter = data.rbegin(); + model_iter != data.rend(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Prev(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestRandomAccess(Random* rnd, + const std::vector& keys, + const KVMap& data) { + static const bool kVerbose = false; + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + KVMap::const_iterator model_iter = data.begin(); + if (kVerbose) fprintf(stderr, "---\n"); + for (int i = 0; i < 200; i++) { + const int toss = rnd->Uniform(5); + switch (toss) { + case 0: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Next\n"); + iter->Next(); + ++model_iter; + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 1: { + if (kVerbose) fprintf(stderr, "SeekToFirst\n"); + iter->SeekToFirst(); + model_iter = data.begin(); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 2: { + std::string key = PickRandomKey(rnd, keys); + model_iter = data.lower_bound(key); + if (kVerbose) fprintf(stderr, "Seek '%s'\n", + EscapeString(key).c_str()); + iter->Seek(Slice(key)); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 3: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Prev\n"); + iter->Prev(); + if (model_iter == data.begin()) { + model_iter = data.end(); // Wrap around to invalid value + } else { + --model_iter; + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 4: { + if (kVerbose) fprintf(stderr, "SeekToLast\n"); + iter->SeekToLast(); + if (keys.empty()) { + model_iter = data.end(); + } else { + std::string last = data.rbegin()->first; + model_iter = data.lower_bound(last); + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + } + } + delete iter; + } + + std::string ToString(const KVMap& data, const KVMap::const_iterator& it) { + if (it == data.end()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const KVMap& data, + const KVMap::const_reverse_iterator& it) { + if (it == data.rend()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const Iterator* it) { + if (!it->Valid()) { + return "END"; + } else { + return "'" + it->key().ToString() + "->" + it->value().ToString() + "'"; + } + } + + std::string PickRandomKey(Random* rnd, const std::vector& keys) { + if (keys.empty()) { + return "foo"; + } else { + const int index = rnd->Uniform(keys.size()); + std::string result = keys[index]; + switch (rnd->Uniform(3)) { + case 0: + // Return an existing key + break; + case 1: { + // Attempt to return something smaller than an existing key + if (result.size() > 0 && result[result.size()-1] > '\0') { + result[result.size()-1]--; + } + break; + } + case 2: { + // Return something larger than an existing key + Increment(options_.comparator, &result); + break; + } + } + return result; + } + } + + // Returns NULL if not running against a DB + DB* db() const { return constructor_->db(); } + + private: + Options options_; + Constructor* constructor_; +}; + +// Test the empty key +TEST(Harness, SimpleEmptyKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Add("", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSingle) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 2); + Add("abc", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleMulti) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 3); + Add("abc", "v"); + Add("abcd", "v"); + Add("ac", "v2"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSpecialKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 4); + Add("\xff\xff", "v3"); + Test(&rnd); + } +} + +TEST(Harness, Randomized) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 5); + for (int num_entries = 0; num_entries < 2000; + num_entries += (num_entries < 50 ? 1 : 200)) { + if ((num_entries % 10) == 0) { + fprintf(stderr, "case %d of %d: num_entries = %d\n", + (i + 1), int(kNumTestArgs), num_entries); + } + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + } + } +} + +TEST(Harness, RandomizedLongDB) { + Random rnd(test::RandomSeed()); + TestArgs args = { DB_TEST, false, 16 }; + Init(args); + int num_entries = 100000; + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + + // We must have created enough data to force merging + int files = 0; + for (int level = 0; level < config::kNumLevels; level++) { + std::string value; + char name[100]; + snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level); + ASSERT_TRUE(db()->GetProperty(name, &value)); + files += atoi(value.c_str()); + } + ASSERT_GT(files, 0); +} + +class MemTableTest { }; + +TEST(MemTableTest, Simple) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* memtable = new MemTable(cmp); + memtable->Ref(); + WriteBatch batch; + WriteBatchInternal::SetSequence(&batch, 100); + batch.Put(std::string("k1"), std::string("v1")); + batch.Put(std::string("k2"), std::string("v2")); + batch.Put(std::string("k3"), std::string("v3")); + batch.Put(std::string("largekey"), std::string("vlarge")); + ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok()); + + Iterator* iter = memtable->NewIterator(); + iter->SeekToFirst(); + while (iter->Valid()) { + fprintf(stderr, "key: '%s' -> '%s'\n", + iter->key().ToString().c_str(), + iter->value().ToString().c_str()); + iter->Next(); + } + + delete iter; + memtable->Unref(); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +class TableTest { }; + +TEST(TableTest, ApproximateOffsetOfPlain) { + TableConstructor c(BytewiseComparator()); + c.Add("k01", "hello"); + c.Add("k02", "hello2"); + c.Add("k03", std::string(10000, 'x')); + c.Add("k04", std::string(200000, 'x')); + c.Add("k05", std::string(300000, 'x')); + c.Add("k06", "hello3"); + c.Add("k07", std::string(100000, 'x')); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kNoCompression; + c.Finish(options, &keys, &kvmap); + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000)); + +} + +static bool SnappyCompressionSupported() { + std::string out; + Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + return port::Snappy_Compress(in.data(), in.size(), &out); +} + +TEST(TableTest, ApproximateOffsetOfCompressed) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + + Random rnd(301); + TableConstructor c(BytewiseComparator()); + std::string tmp; + c.Add("k01", "hello"); + c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + c.Add("k03", "hello3"); + c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kSnappyCompression; + c.Finish(options, &keys, &kvmap); + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/table/two_level_iterator.cc b/table/two_level_iterator.cc new file mode 100644 index 000000000..7822ebab9 --- /dev/null +++ b/table/two_level_iterator.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/two_level_iterator.h" + +#include "leveldb/table.h" +#include "table/block.h" +#include "table/format.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { + +typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); + +class TwoLevelIterator: public Iterator { + public: + TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options); + + virtual ~TwoLevelIterator(); + + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + virtual void Next(); + virtual void Prev(); + + virtual bool Valid() const { + return data_iter_.Valid(); + } + virtual Slice key() const { + assert(Valid()); + return data_iter_.key(); + } + virtual Slice value() const { + assert(Valid()); + return data_iter_.value(); + } + virtual Status status() const { + // It'd be nice if status() returned a const Status& instead of a Status + if (!index_iter_.status().ok()) { + return index_iter_.status(); + } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) { + return data_iter_.status(); + } else { + return status_; + } + } + + private: + void SaveError(const Status& s) { + if (status_.ok() && !s.ok()) status_ = s; + } + void SkipEmptyDataBlocksForward(); + void SkipEmptyDataBlocksBackward(); + void SetDataIterator(Iterator* data_iter); + void InitDataBlock(); + + BlockFunction block_function_; + void* arg_; + const ReadOptions options_; + Status status_; + IteratorWrapper index_iter_; + IteratorWrapper data_iter_; // May be NULL + // If data_iter_ is non-NULL, then "data_block_handle_" holds the + // "index_value" passed to block_function_ to create the data_iter_. + std::string data_block_handle_; +}; + +TwoLevelIterator::TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) + : block_function_(block_function), + arg_(arg), + options_(options), + index_iter_(index_iter), + data_iter_(NULL) { +} + +TwoLevelIterator::~TwoLevelIterator() { +} + +void TwoLevelIterator::Seek(const Slice& target) { + index_iter_.Seek(target); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.Seek(target); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToFirst() { + index_iter_.SeekToFirst(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToLast() { + index_iter_.SeekToLast(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + SkipEmptyDataBlocksBackward(); +} + +void TwoLevelIterator::Next() { + assert(Valid()); + data_iter_.Next(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::Prev() { + assert(Valid()); + data_iter_.Prev(); + SkipEmptyDataBlocksBackward(); +} + + +void TwoLevelIterator::SkipEmptyDataBlocksForward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Next(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + } +} + +void TwoLevelIterator::SkipEmptyDataBlocksBackward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Prev(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + } +} + +void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { + if (data_iter_.iter() != NULL) SaveError(data_iter_.status()); + data_iter_.Set(data_iter); +} + +void TwoLevelIterator::InitDataBlock() { + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + } else { + Slice handle = index_iter_.value(); + if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) { + // data_iter_ is already constructed with this iterator, so + // no need to change anything + } else { + Iterator* iter = (*block_function_)(arg_, options_, handle); + data_block_handle_.assign(handle.data(), handle.size()); + SetDataIterator(iter); + } + } +} + +} // namespace + +Iterator* NewTwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) { + return new TwoLevelIterator(index_iter, block_function, arg, options); +} + +} // namespace leveldb diff --git a/table/two_level_iterator.h b/table/two_level_iterator.h new file mode 100644 index 000000000..629ca3452 --- /dev/null +++ b/table/two_level_iterator.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ +#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ + +#include "leveldb/iterator.h" + +namespace leveldb { + +struct ReadOptions; + +// Return a new two level iterator. A two-level iterator contains an +// index iterator whose values point to a sequence of blocks where +// each block is itself a sequence of key,value pairs. The returned +// two-level iterator yields the concatenation of all key/value pairs +// in the sequence of blocks. Takes ownership of "index_iter" and +// will delete it when no longer needed. +// +// Uses a supplied function to convert an index_iter value into +// an iterator over the contents of the corresponding block. +extern Iterator* NewTwoLevelIterator( + Iterator* index_iter, + Iterator* (*block_function)( + void* arg, + const ReadOptions& options, + const Slice& index_value), + void* arg, + const ReadOptions& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/util/arena.cc b/util/arena.cc new file mode 100644 index 000000000..9551d6a3a --- /dev/null +++ b/util/arena.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" +#include + +namespace leveldb { + +static const int kBlockSize = 4096; + +Arena::Arena() { + blocks_memory_ = 0; + alloc_ptr_ = NULL; // First allocation will allocate a block + alloc_bytes_remaining_ = 0; +} + +Arena::~Arena() { + for (size_t i = 0; i < blocks_.size(); i++) { + delete[] blocks_[i]; + } +} + +char* Arena::AllocateFallback(size_t bytes) { + if (bytes > kBlockSize / 4) { + // Object is more than a quarter of our block size. Allocate it separately + // to avoid wasting too much space in leftover bytes. + char* result = AllocateNewBlock(bytes); + return result; + } + + // We waste the remaining space in the current block. + alloc_ptr_ = AllocateNewBlock(kBlockSize); + alloc_bytes_remaining_ = kBlockSize; + + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; +} + +char* Arena::AllocateAligned(size_t bytes) { + const int align = sizeof(void*); // We'll align to pointer size + assert((align & (align-1)) == 0); // Pointer size should be a power of 2 + size_t current_mod = reinterpret_cast(alloc_ptr_) & (align-1); + size_t slop = (current_mod == 0 ? 0 : align - current_mod); + size_t needed = bytes + slop; + char* result; + if (needed <= alloc_bytes_remaining_) { + result = alloc_ptr_ + slop; + alloc_ptr_ += needed; + alloc_bytes_remaining_ -= needed; + } else { + // AllocateFallback always returned aligned memory + result = AllocateFallback(bytes); + } + assert((reinterpret_cast(result) & (align-1)) == 0); + return result; +} + +char* Arena::AllocateNewBlock(size_t block_bytes) { + char* result = new char[block_bytes]; + blocks_memory_ += block_bytes; + blocks_.push_back(result); + return result; +} + +} // namespace leveldb diff --git a/util/arena.h b/util/arena.h new file mode 100644 index 000000000..8f7dde226 --- /dev/null +++ b/util/arena.h @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_ +#define STORAGE_LEVELDB_UTIL_ARENA_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Arena { + public: + Arena(); + ~Arena(); + + // Return a pointer to a newly allocated memory block of "bytes" bytes. + char* Allocate(size_t bytes); + + // Allocate memory with the normal alignment guarantees provided by malloc + char* AllocateAligned(size_t bytes); + + // Returns an estimate of the total memory usage of data allocated + // by the arena (including space allocated but not yet used for user + // allocations). + size_t MemoryUsage() const { + return blocks_memory_ + blocks_.capacity() * sizeof(char*); + } + + private: + char* AllocateFallback(size_t bytes); + char* AllocateNewBlock(size_t block_bytes); + + // Allocation state + char* alloc_ptr_; + size_t alloc_bytes_remaining_; + + // Array of new[] allocated memory blocks + std::vector blocks_; + + // Bytes of memory in blocks allocated so far + size_t blocks_memory_; + + // No copying allowed + Arena(const Arena&); + void operator=(const Arena&); +}; + +inline char* Arena::Allocate(size_t bytes) { + // The semantics of what to return are a bit messy if we allow + // 0-byte allocations, so we disallow them here (we don't need + // them for our internal use). + assert(bytes > 0); + if (bytes <= alloc_bytes_remaining_) { + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; + } + return AllocateFallback(bytes); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/util/arena_test.cc b/util/arena_test.cc new file mode 100644 index 000000000..63d177803 --- /dev/null +++ b/util/arena_test.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" + +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +class ArenaTest { }; + +TEST(ArenaTest, Empty) { + Arena arena; +} + +TEST(ArenaTest, Simple) { + std::vector > allocated; + Arena arena; + const int N = 100000; + size_t bytes = 0; + Random rnd(301); + for (int i = 0; i < N; i++) { + size_t s; + if (i % (N / 10) == 0) { + s = i; + } else { + s = rnd.OneIn(4000) ? rnd.Uniform(6000) : + (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20)); + } + if (s == 0) { + // Our arena disallows size 0 allocations. + s = 1; + } + char* r; + if (rnd.OneIn(10)) { + r = arena.AllocateAligned(s); + } else { + r = arena.Allocate(s); + } + + for (int b = 0; b < s; b++) { + // Fill the "i"th allocation with a known bit pattern + r[b] = i % 256; + } + bytes += s; + allocated.push_back(std::make_pair(s, r)); + ASSERT_GE(arena.MemoryUsage(), bytes); + if (i > N/10) { + ASSERT_LE(arena.MemoryUsage(), bytes * 1.10); + } + } + for (int i = 0; i < allocated.size(); i++) { + size_t num_bytes = allocated[i].first; + const char* p = allocated[i].second; + for (int b = 0; b < num_bytes; b++) { + // Check the "i"th allocation for the known bit pattern + ASSERT_EQ(int(p[b]) & 0xff, i % 256); + } + } +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/bloom.cc b/util/bloom.cc new file mode 100644 index 000000000..d7941cd21 --- /dev/null +++ b/util/bloom.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +namespace { +static uint32_t BloomHash(const Slice& key) { + return Hash(key.data(), key.size(), 0xbc9f1d34); +} + +class BloomFilterPolicy : public FilterPolicy { + private: + size_t bits_per_key_; + size_t k_; + + public: + explicit BloomFilterPolicy(int bits_per_key) + : bits_per_key_(bits_per_key) { + // We intentionally round down to reduce probing cost a little bit + k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) + if (k_ < 1) k_ = 1; + if (k_ > 30) k_ = 30; + } + + virtual const char* Name() const { + return "leveldb.BuiltinBloomFilter"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Compute bloom filter size (in both bits and bytes) + size_t bits = n * bits_per_key_; + + // For small n, we can see a very high false positive rate. Fix it + // by enforcing a minimum bloom filter length. + if (bits < 64) bits = 64; + + size_t bytes = (bits + 7) / 8; + bits = bytes * 8; + + const size_t init_size = dst->size(); + dst->resize(init_size + bytes, 0); + dst->push_back(static_cast(k_)); // Remember # of probes in filter + char* array = &(*dst)[init_size]; + for (size_t i = 0; i < n; i++) { + // Use double-hashing to generate a sequence of hash values. + // See analysis in [Kirsch,Mitzenmacher 2006]. + uint32_t h = BloomHash(keys[i]); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k_; j++) { + const uint32_t bitpos = h % bits; + array[bitpos/8] |= (1 << (bitpos % 8)); + h += delta; + } + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { + const size_t len = bloom_filter.size(); + if (len < 2) return false; + + const char* array = bloom_filter.data(); + const size_t bits = (len - 1) * 8; + + // Use the encoded k so that we can read filters generated by + // bloom filters created using different parameters. + const size_t k = array[len-1]; + if (k > 30) { + // Reserved for potentially new encodings for short bloom filters. + // Consider it a match. + return true; + } + + uint32_t h = BloomHash(key); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k; j++) { + const uint32_t bitpos = h % bits; + if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false; + h += delta; + } + return true; + } +}; +} + +const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { + return new BloomFilterPolicy(bits_per_key); +} + +} // namespace leveldb diff --git a/util/bloom_test.cc b/util/bloom_test.cc new file mode 100644 index 000000000..0bf8e8d6e --- /dev/null +++ b/util/bloom_test.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "util/coding.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kVerbose = 1; + +static Slice Key(int i, char* buffer) { + EncodeFixed32(buffer, i); + return Slice(buffer, sizeof(uint32_t)); +} + +class BloomTest { + private: + const FilterPolicy* policy_; + std::string filter_; + std::vector keys_; + + public: + BloomTest() : policy_(NewBloomFilterPolicy(10)) { } + + ~BloomTest() { + delete policy_; + } + + void Reset() { + keys_.clear(); + filter_.clear(); + } + + void Add(const Slice& s) { + keys_.push_back(s.ToString()); + } + + void Build() { + std::vector key_slices; + for (size_t i = 0; i < keys_.size(); i++) { + key_slices.push_back(Slice(keys_[i])); + } + filter_.clear(); + policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_); + keys_.clear(); + if (kVerbose >= 2) DumpFilter(); + } + + size_t FilterSize() const { + return filter_.size(); + } + + void DumpFilter() { + fprintf(stderr, "F("); + for (size_t i = 0; i+1 < filter_.size(); i++) { + const unsigned int c = static_cast(filter_[i]); + for (int j = 0; j < 8; j++) { + fprintf(stderr, "%c", (c & (1 <KeyMayMatch(s, filter_); + } + + double FalsePositiveRate() { + char buffer[sizeof(int)]; + int result = 0; + for (int i = 0; i < 10000; i++) { + if (Matches(Key(i + 1000000000, buffer))) { + result++; + } + } + return result / 10000.0; + } +}; + +TEST(BloomTest, EmptyFilter) { + ASSERT_TRUE(! Matches("hello")); + ASSERT_TRUE(! Matches("world")); +} + +TEST(BloomTest, Small) { + Add("hello"); + Add("world"); + ASSERT_TRUE(Matches("hello")); + ASSERT_TRUE(Matches("world")); + ASSERT_TRUE(! Matches("x")); + ASSERT_TRUE(! Matches("foo")); +} + +static int NextLength(int length) { + if (length < 10) { + length += 1; + } else if (length < 100) { + length += 10; + } else if (length < 1000) { + length += 100; + } else { + length += 1000; + } + return length; +} + +TEST(BloomTest, VaryingLengths) { + char buffer[sizeof(int)]; + + // Count number of filters that significantly exceed the false positive rate + int mediocre_filters = 0; + int good_filters = 0; + + for (int length = 1; length <= 10000; length = NextLength(length)) { + Reset(); + for (int i = 0; i < length; i++) { + Add(Key(i, buffer)); + } + Build(); + + ASSERT_LE(FilterSize(), (length * 10 / 8) + 40) << length; + + // All added keys must match + for (int i = 0; i < length; i++) { + ASSERT_TRUE(Matches(Key(i, buffer))) + << "Length " << length << "; key " << i; + } + + // Check false positive rate + double rate = FalsePositiveRate(); + if (kVerbose >= 1) { + fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", + rate*100.0, length, static_cast(FilterSize())); + } + ASSERT_LE(rate, 0.02); // Must not be over 2% + if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often + else good_filters++; + } + if (kVerbose >= 1) { + fprintf(stderr, "Filters: %d good, %d mediocre\n", + good_filters, mediocre_filters); + } + ASSERT_LE(mediocre_filters, good_filters/5); +} + +// Different bits-per-byte + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/cache.cc b/util/cache.cc new file mode 100644 index 000000000..24f1f63f4 --- /dev/null +++ b/util/cache.cc @@ -0,0 +1,328 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include + +#include "leveldb/cache.h" +#include "port/port.h" +#include "util/hash.h" +#include "util/mutexlock.h" + +namespace leveldb { + +Cache::~Cache() { +} + +namespace { + +// LRU cache implementation + +// An entry is a variable length heap-allocated structure. Entries +// are kept in a circular doubly linked list ordered by access time. +struct LRUHandle { + void* value; + void (*deleter)(const Slice&, void* value); + LRUHandle* next_hash; + LRUHandle* next; + LRUHandle* prev; + size_t charge; // TODO(opt): Only allow uint32_t? + size_t key_length; + uint32_t refs; + uint32_t hash; // Hash of key(); used for fast sharding and comparisons + char key_data[1]; // Beginning of key + + Slice key() const { + // For cheaper lookups, we allow a temporary Handle object + // to store a pointer to a key in "value". + if (next == this) { + return *(reinterpret_cast(value)); + } else { + return Slice(key_data, key_length); + } + } +}; + +// We provide our own simple hash table since it removes a whole bunch +// of porting hacks and is also faster than some of the built-in hash +// table implementations in some of the compiler/runtime combinations +// we have tested. E.g., readrandom speeds up by ~5% over the g++ +// 4.4.3's builtin hashtable. +class HandleTable { + public: + HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); } + ~HandleTable() { delete[] list_; } + + LRUHandle* Lookup(const Slice& key, uint32_t hash) { + return *FindPointer(key, hash); + } + + LRUHandle* Insert(LRUHandle* h) { + LRUHandle** ptr = FindPointer(h->key(), h->hash); + LRUHandle* old = *ptr; + h->next_hash = (old == NULL ? NULL : old->next_hash); + *ptr = h; + if (old == NULL) { + ++elems_; + if (elems_ > length_) { + // Since each cache entry is fairly large, we aim for a small + // average linked list length (<= 1). + Resize(); + } + } + return old; + } + + LRUHandle* Remove(const Slice& key, uint32_t hash) { + LRUHandle** ptr = FindPointer(key, hash); + LRUHandle* result = *ptr; + if (result != NULL) { + *ptr = result->next_hash; + --elems_; + } + return result; + } + + private: + // The table consists of an array of buckets where each bucket is + // a linked list of cache entries that hash into the bucket. + uint32_t length_; + uint32_t elems_; + LRUHandle** list_; + + // Return a pointer to slot that points to a cache entry that + // matches key/hash. If there is no such cache entry, return a + // pointer to the trailing slot in the corresponding linked list. + LRUHandle** FindPointer(const Slice& key, uint32_t hash) { + LRUHandle** ptr = &list_[hash & (length_ - 1)]; + while (*ptr != NULL && + ((*ptr)->hash != hash || key != (*ptr)->key())) { + ptr = &(*ptr)->next_hash; + } + return ptr; + } + + void Resize() { + uint32_t new_length = 4; + while (new_length < elems_) { + new_length *= 2; + } + LRUHandle** new_list = new LRUHandle*[new_length]; + memset(new_list, 0, sizeof(new_list[0]) * new_length); + uint32_t count = 0; + for (uint32_t i = 0; i < length_; i++) { + LRUHandle* h = list_[i]; + while (h != NULL) { + LRUHandle* next = h->next_hash; + Slice key = h->key(); + uint32_t hash = h->hash; + LRUHandle** ptr = &new_list[hash & (new_length - 1)]; + h->next_hash = *ptr; + *ptr = h; + h = next; + count++; + } + } + assert(elems_ == count); + delete[] list_; + list_ = new_list; + length_ = new_length; + } +}; + +// A single shard of sharded cache. +class LRUCache { + public: + LRUCache(); + ~LRUCache(); + + // Separate from constructor so caller can easily make an array of LRUCache + void SetCapacity(size_t capacity) { capacity_ = capacity; } + + // Like Cache methods, but with an extra "hash" parameter. + Cache::Handle* Insert(const Slice& key, uint32_t hash, + void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)); + Cache::Handle* Lookup(const Slice& key, uint32_t hash); + void Release(Cache::Handle* handle); + void Erase(const Slice& key, uint32_t hash); + + private: + void LRU_Remove(LRUHandle* e); + void LRU_Append(LRUHandle* e); + void Unref(LRUHandle* e); + + // Initialized before use. + size_t capacity_; + + // mutex_ protects the following state. + port::Mutex mutex_; + size_t usage_; + uint64_t last_id_; + + // Dummy head of LRU list. + // lru.prev is newest entry, lru.next is oldest entry. + LRUHandle lru_; + + HandleTable table_; +}; + +LRUCache::LRUCache() + : usage_(0), + last_id_(0) { + // Make empty circular linked list + lru_.next = &lru_; + lru_.prev = &lru_; +} + +LRUCache::~LRUCache() { + for (LRUHandle* e = lru_.next; e != &lru_; ) { + LRUHandle* next = e->next; + assert(e->refs == 1); // Error if caller has an unreleased handle + Unref(e); + e = next; + } +} + +void LRUCache::Unref(LRUHandle* e) { + assert(e->refs > 0); + e->refs--; + if (e->refs <= 0) { + usage_ -= e->charge; + (*e->deleter)(e->key(), e->value); + free(e); + } +} + +void LRUCache::LRU_Remove(LRUHandle* e) { + e->next->prev = e->prev; + e->prev->next = e->next; +} + +void LRUCache::LRU_Append(LRUHandle* e) { + // Make "e" newest entry by inserting just before lru_ + e->next = &lru_; + e->prev = lru_.prev; + e->prev->next = e; + e->next->prev = e; +} + +Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Lookup(key, hash); + if (e != NULL) { + e->refs++; + LRU_Remove(e); + LRU_Append(e); + } + return reinterpret_cast(e); +} + +void LRUCache::Release(Cache::Handle* handle) { + MutexLock l(&mutex_); + Unref(reinterpret_cast(handle)); +} + +Cache::Handle* LRUCache::Insert( + const Slice& key, uint32_t hash, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + MutexLock l(&mutex_); + + LRUHandle* e = reinterpret_cast( + malloc(sizeof(LRUHandle)-1 + key.size())); + e->value = value; + e->deleter = deleter; + e->charge = charge; + e->key_length = key.size(); + e->hash = hash; + e->refs = 2; // One from LRUCache, one for the returned handle + memcpy(e->key_data, key.data(), key.size()); + LRU_Append(e); + usage_ += charge; + + LRUHandle* old = table_.Insert(e); + if (old != NULL) { + LRU_Remove(old); + Unref(old); + } + + while (usage_ > capacity_ && lru_.next != &lru_) { + LRUHandle* old = lru_.next; + LRU_Remove(old); + table_.Remove(old->key(), old->hash); + Unref(old); + } + + return reinterpret_cast(e); +} + +void LRUCache::Erase(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Remove(key, hash); + if (e != NULL) { + LRU_Remove(e); + Unref(e); + } +} + +static const int kNumShardBits = 4; +static const int kNumShards = 1 << kNumShardBits; + +class ShardedLRUCache : public Cache { + private: + LRUCache shard_[kNumShards]; + port::Mutex id_mutex_; + uint64_t last_id_; + + static inline uint32_t HashSlice(const Slice& s) { + return Hash(s.data(), s.size(), 0); + } + + static uint32_t Shard(uint32_t hash) { + return hash >> (32 - kNumShardBits); + } + + public: + explicit ShardedLRUCache(size_t capacity) + : last_id_(0) { + const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; + for (int s = 0; s < kNumShards; s++) { + shard_[s].SetCapacity(per_shard); + } + } + virtual ~ShardedLRUCache() { } + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); + } + virtual Handle* Lookup(const Slice& key) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Lookup(key, hash); + } + virtual void Release(Handle* handle) { + LRUHandle* h = reinterpret_cast(handle); + shard_[Shard(h->hash)].Release(handle); + } + virtual void Erase(const Slice& key) { + const uint32_t hash = HashSlice(key); + shard_[Shard(hash)].Erase(key, hash); + } + virtual void* Value(Handle* handle) { + return reinterpret_cast(handle)->value; + } + virtual uint64_t NewId() { + MutexLock l(&id_mutex_); + return ++(last_id_); + } +}; + +} // end anonymous namespace + +Cache* NewLRUCache(size_t capacity) { + return new ShardedLRUCache(capacity); +} + +} // namespace leveldb diff --git a/util/cache_test.cc b/util/cache_test.cc new file mode 100644 index 000000000..43716715a --- /dev/null +++ b/util/cache_test.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/cache.h" + +#include +#include "util/coding.h" +#include "util/testharness.h" + +namespace leveldb { + +// Conversions between numeric keys/values and the types expected by Cache. +static std::string EncodeKey(int k) { + std::string result; + PutFixed32(&result, k); + return result; +} +static int DecodeKey(const Slice& k) { + assert(k.size() == 4); + return DecodeFixed32(k.data()); +} +static void* EncodeValue(uintptr_t v) { return reinterpret_cast(v); } +static int DecodeValue(void* v) { return reinterpret_cast(v); } + +class CacheTest { + public: + static CacheTest* current_; + + static void Deleter(const Slice& key, void* v) { + current_->deleted_keys_.push_back(DecodeKey(key)); + current_->deleted_values_.push_back(DecodeValue(v)); + } + + static const int kCacheSize = 1000; + std::vector deleted_keys_; + std::vector deleted_values_; + Cache* cache_; + + CacheTest() : cache_(NewLRUCache(kCacheSize)) { + current_ = this; + } + + ~CacheTest() { + delete cache_; + } + + int Lookup(int key) { + Cache::Handle* handle = cache_->Lookup(EncodeKey(key)); + const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle)); + if (handle != NULL) { + cache_->Release(handle); + } + return r; + } + + void Insert(int key, int value, int charge = 1) { + cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge, + &CacheTest::Deleter)); + } + + void Erase(int key) { + cache_->Erase(EncodeKey(key)); + } +}; +CacheTest* CacheTest::current_; + +TEST(CacheTest, HitAndMiss) { + ASSERT_EQ(-1, Lookup(100)); + + Insert(100, 101); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(200, 201); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(100, 102); + ASSERT_EQ(102, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); +} + +TEST(CacheTest, Erase) { + Erase(200); + ASSERT_EQ(0, deleted_keys_.size()); + + Insert(100, 101); + Insert(200, 201); + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); +} + +TEST(CacheTest, EntriesArePinned) { + Insert(100, 101); + Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); + + Insert(100, 102); + Cache::Handle* h2 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(102, DecodeValue(cache_->Value(h2))); + ASSERT_EQ(0, deleted_keys_.size()); + + cache_->Release(h1); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(1, deleted_keys_.size()); + + cache_->Release(h2); + ASSERT_EQ(2, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[1]); + ASSERT_EQ(102, deleted_values_[1]); +} + +TEST(CacheTest, EvictionPolicy) { + Insert(100, 101); + Insert(200, 201); + + // Frequently used entry must be kept around + for (int i = 0; i < kCacheSize + 100; i++) { + Insert(1000+i, 2000+i); + ASSERT_EQ(2000+i, Lookup(1000+i)); + ASSERT_EQ(101, Lookup(100)); + } + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); +} + +TEST(CacheTest, HeavyEntries) { + // Add a bunch of light and heavy entries and then count the combined + // size of items still in the cache, which must be approximately the + // same as the total capacity. + const int kLight = 1; + const int kHeavy = 10; + int added = 0; + int index = 0; + while (added < 2*kCacheSize) { + const int weight = (index & 1) ? kLight : kHeavy; + Insert(index, 1000+index, weight); + added += weight; + index++; + } + + int cached_weight = 0; + for (int i = 0; i < index; i++) { + const int weight = (i & 1 ? kLight : kHeavy); + int r = Lookup(i); + if (r >= 0) { + cached_weight += weight; + ASSERT_EQ(1000+i, r); + } + } + ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10); +} + +TEST(CacheTest, NewId) { + uint64_t a = cache_->NewId(); + uint64_t b = cache_->NewId(); + ASSERT_NE(a, b); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/coding.cc b/util/coding.cc new file mode 100644 index 000000000..21e3186d5 --- /dev/null +++ b/util/coding.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +namespace leveldb { + +void EncodeFixed32(char* buf, uint32_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + } +} + +void EncodeFixed64(char* buf, uint64_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + buf[4] = (value >> 32) & 0xff; + buf[5] = (value >> 40) & 0xff; + buf[6] = (value >> 48) & 0xff; + buf[7] = (value >> 56) & 0xff; + } +} + +void PutFixed32(std::string* dst, uint32_t value) { + char buf[sizeof(value)]; + EncodeFixed32(buf, value); + dst->append(buf, sizeof(buf)); +} + +void PutFixed64(std::string* dst, uint64_t value) { + char buf[sizeof(value)]; + EncodeFixed64(buf, value); + dst->append(buf, sizeof(buf)); +} + +char* EncodeVarint32(char* dst, uint32_t v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(dst); + static const int B = 128; + if (v < (1<<7)) { + *(ptr++) = v; + } else if (v < (1<<14)) { + *(ptr++) = v | B; + *(ptr++) = v>>7; + } else if (v < (1<<21)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = v>>14; + } else if (v < (1<<28)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = v>>21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = (v>>21) | B; + *(ptr++) = v>>28; + } + return reinterpret_cast(ptr); +} + +void PutVarint32(std::string* dst, uint32_t v) { + char buf[5]; + char* ptr = EncodeVarint32(buf, v); + dst->append(buf, ptr - buf); +} + +char* EncodeVarint64(char* dst, uint64_t v) { + static const int B = 128; + unsigned char* ptr = reinterpret_cast(dst); + while (v >= B) { + *(ptr++) = (v & (B-1)) | B; + v >>= 7; + } + *(ptr++) = static_cast(v); + return reinterpret_cast(ptr); +} + +void PutVarint64(std::string* dst, uint64_t v) { + char buf[10]; + char* ptr = EncodeVarint64(buf, v); + dst->append(buf, ptr - buf); +} + +void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { + PutVarint32(dst, value.size()); + dst->append(value.data(), value.size()); +} + +int VarintLength(uint64_t v) { + int len = 1; + while (v >= 128) { + v >>= 7; + len++; + } + return len; +} + +const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value) { + uint32_t result = 0; + for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { + uint32_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint32(Slice* input, uint32_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint32Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { + uint64_t result = 0; + for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { + uint64_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint64(Slice* input, uint64_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint64Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetLengthPrefixedSlice(const char* p, const char* limit, + Slice* result) { + uint32_t len; + p = GetVarint32Ptr(p, limit, &len); + if (p == NULL) return NULL; + if (p + len > limit) return NULL; + *result = Slice(p, len); + return p + len; +} + +bool GetLengthPrefixedSlice(Slice* input, Slice* result) { + uint32_t len; + if (GetVarint32(input, &len) && + input->size() >= len) { + *result = Slice(input->data(), len); + input->remove_prefix(len); + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/util/coding.h b/util/coding.h new file mode 100644 index 000000000..3993c4a75 --- /dev/null +++ b/util/coding.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Endian-neutral encoding: +// * Fixed-length numbers are encoded with least-significant byte first +// * In addition we support variable length "varint" encoding +// * Strings are encoded prefixed by their length in varint format + +#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ +#define STORAGE_LEVELDB_UTIL_CODING_H_ + +#include +#include +#include +#include "leveldb/slice.h" +#include "port/port.h" + +namespace leveldb { + +// Standard Put... routines append to a string +extern void PutFixed32(std::string* dst, uint32_t value); +extern void PutFixed64(std::string* dst, uint64_t value); +extern void PutVarint32(std::string* dst, uint32_t value); +extern void PutVarint64(std::string* dst, uint64_t value); +extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value); + +// Standard Get... routines parse a value from the beginning of a Slice +// and advance the slice past the parsed value. +extern bool GetVarint32(Slice* input, uint32_t* value); +extern bool GetVarint64(Slice* input, uint64_t* value); +extern bool GetLengthPrefixedSlice(Slice* input, Slice* result); + +// Pointer-based variants of GetVarint... These either store a value +// in *v and return a pointer just past the parsed value, or return +// NULL on error. These routines only look at bytes in the range +// [p..limit-1] +extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v); +extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v); + +// Returns the length of the varint32 or varint64 encoding of "v" +extern int VarintLength(uint64_t v); + +// Lower-level versions of Put... that write directly into a character buffer +// REQUIRES: dst has enough space for the value being written +extern void EncodeFixed32(char* dst, uint32_t value); +extern void EncodeFixed64(char* dst, uint64_t value); + +// Lower-level versions of Put... that write directly into a character buffer +// and return a pointer just past the last byte written. +// REQUIRES: dst has enough space for the value being written +extern char* EncodeVarint32(char* dst, uint32_t value); +extern char* EncodeVarint64(char* dst, uint64_t value); + +// Lower-level versions of Get... that read directly from a character buffer +// without any bounds checking. + +inline uint32_t DecodeFixed32(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint32_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + return ((static_cast(static_cast(ptr[0]))) + | (static_cast(static_cast(ptr[1])) << 8) + | (static_cast(static_cast(ptr[2])) << 16) + | (static_cast(static_cast(ptr[3])) << 24)); + } +} + +inline uint64_t DecodeFixed64(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint64_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + uint64_t lo = DecodeFixed32(ptr); + uint64_t hi = DecodeFixed32(ptr + 4); + return (hi << 32) | lo; + } +} + +// Internal routine for use by fallback path of GetVarint32Ptr +extern const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value); +inline const char* GetVarint32Ptr(const char* p, + const char* limit, + uint32_t* value) { + if (p < limit) { + uint32_t result = *(reinterpret_cast(p)); + if ((result & 128) == 0) { + *value = result; + return p + 1; + } + } + return GetVarint32PtrFallback(p, limit, value); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/util/coding_test.cc b/util/coding_test.cc new file mode 100644 index 000000000..2c52b17b6 --- /dev/null +++ b/util/coding_test.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +#include "util/testharness.h" + +namespace leveldb { + +class Coding { }; + +TEST(Coding, Fixed32) { + std::string s; + for (uint32_t v = 0; v < 100000; v++) { + PutFixed32(&s, v); + } + + const char* p = s.data(); + for (uint32_t v = 0; v < 100000; v++) { + uint32_t actual = DecodeFixed32(p); + ASSERT_EQ(v, actual); + p += sizeof(uint32_t); + } +} + +TEST(Coding, Fixed64) { + std::string s; + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + PutFixed64(&s, v - 1); + PutFixed64(&s, v + 0); + PutFixed64(&s, v + 1); + } + + const char* p = s.data(); + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + uint64_t actual; + actual = DecodeFixed64(p); + ASSERT_EQ(v-1, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+0, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+1, actual); + p += sizeof(uint64_t); + } +} + +// Test that encoding routines generate little-endian encodings +TEST(Coding, EncodingOutput) { + std::string dst; + PutFixed32(&dst, 0x04030201); + ASSERT_EQ(4, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + + dst.clear(); + PutFixed64(&dst, 0x0807060504030201ull); + ASSERT_EQ(8, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + ASSERT_EQ(0x05, static_cast(dst[4])); + ASSERT_EQ(0x06, static_cast(dst[5])); + ASSERT_EQ(0x07, static_cast(dst[6])); + ASSERT_EQ(0x08, static_cast(dst[7])); +} + +TEST(Coding, Varint32) { + std::string s; + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t v = (i / 32) << (i % 32); + PutVarint32(&s, v); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t expected = (i / 32) << (i % 32); + uint32_t actual; + const char* start = p; + p = GetVarint32Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(expected, actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, s.data() + s.size()); +} + +TEST(Coding, Varint64) { + // Construct the list of values to check + std::vector values; + // Some special values + values.push_back(0); + values.push_back(100); + values.push_back(~static_cast(0)); + values.push_back(~static_cast(0) - 1); + for (uint32_t k = 0; k < 64; k++) { + // Test values near powers of two + const uint64_t power = 1ull << k; + values.push_back(power); + values.push_back(power-1); + values.push_back(power+1); + }; + + std::string s; + for (int i = 0; i < values.size(); i++) { + PutVarint64(&s, values[i]); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (int i = 0; i < values.size(); i++) { + ASSERT_TRUE(p < limit); + uint64_t actual; + const char* start = p; + p = GetVarint64Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(values[i], actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, limit); + +} + +TEST(Coding, Varint32Overflow) { + uint32_t result; + std::string input("\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint32Truncation) { + uint32_t large_value = (1u << 31) + 100; + std::string s; + PutVarint32(&s, large_value); + uint32_t result; + for (int len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Varint64Overflow) { + uint64_t result; + std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint64Truncation) { + uint64_t large_value = (1ull << 63) + 100ull; + std::string s; + PutVarint64(&s, large_value); + uint64_t result; + for (int len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Strings) { + std::string s; + PutLengthPrefixedSlice(&s, Slice("")); + PutLengthPrefixedSlice(&s, Slice("foo")); + PutLengthPrefixedSlice(&s, Slice("bar")); + PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x'))); + + Slice input(s); + Slice v; + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("foo", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("bar", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ(std::string(200, 'x'), v.ToString()); + ASSERT_EQ("", input.ToString()); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/comparator.cc b/util/comparator.cc new file mode 100644 index 000000000..4b7b5724e --- /dev/null +++ b/util/comparator.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" + +namespace leveldb { + +Comparator::~Comparator() { } + +namespace { +class BytewiseComparatorImpl : public Comparator { + public: + BytewiseComparatorImpl() { } + + virtual const char* Name() const { + return "leveldb.BytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return a.compare(b); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Find length of common prefix + size_t min_length = std::min(start->size(), limit.size()); + size_t diff_index = 0; + while ((diff_index < min_length) && + ((*start)[diff_index] == limit[diff_index])) { + diff_index++; + } + + if (diff_index >= min_length) { + // Do not shorten if one string is a prefix of the other + } else { + uint8_t diff_byte = static_cast((*start)[diff_index]); + if (diff_byte < static_cast(0xff) && + diff_byte + 1 < static_cast(limit[diff_index])) { + (*start)[diff_index]++; + start->resize(diff_index + 1); + assert(Compare(*start, limit) < 0); + } + } + } + + virtual void FindShortSuccessor(std::string* key) const { + // Find first character that can be incremented + size_t n = key->size(); + for (size_t i = 0; i < n; i++) { + const uint8_t byte = (*key)[i]; + if (byte != static_cast(0xff)) { + (*key)[i] = byte + 1; + key->resize(i+1); + return; + } + } + // *key is a run of 0xffs. Leave it alone. + } +}; +} // namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static const Comparator* bytewise; + +static void InitModule() { + bytewise = new BytewiseComparatorImpl; +} + +const Comparator* BytewiseComparator() { + port::InitOnce(&once, InitModule); + return bytewise; +} + +} // namespace leveldb diff --git a/util/crc32c.cc b/util/crc32c.cc new file mode 100644 index 000000000..6db9e7707 --- /dev/null +++ b/util/crc32c.cc @@ -0,0 +1,332 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. + +#include "util/crc32c.h" + +#include +#include "util/coding.h" + +namespace leveldb { +namespace crc32c { + +static const uint32_t table0_[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; +static const uint32_t table1_[256] = { + 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, + 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, + 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, + 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, + 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, + 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, + 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, + 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, + 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, + 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, + 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, + 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, + 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, + 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, + 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, + 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, + 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, + 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, + 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, + 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, + 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, + 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, + 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, + 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, + 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, + 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, + 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, + 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, + 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, + 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, + 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, + 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, + 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, + 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, + 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, + 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, + 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, + 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, + 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, + 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, + 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, + 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, + 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, + 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, + 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, + 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, + 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, + 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, + 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, + 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, + 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, + 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, + 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, + 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, + 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, + 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, + 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, + 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, + 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, + 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, + 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, + 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, + 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, + 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 +}; +static const uint32_t table2_[256] = { + 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, + 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, + 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, + 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, + 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, + 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, + 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, + 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, + 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, + 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, + 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, + 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, + 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, + 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, + 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, + 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, + 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, + 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, + 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, + 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, + 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, + 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, + 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, + 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, + 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, + 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, + 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, + 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, + 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, + 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, + 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, + 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, + 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, + 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, + 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, + 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, + 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, + 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, + 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, + 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, + 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, + 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, + 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, + 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, + 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, + 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, + 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, + 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, + 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, + 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, + 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, + 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, + 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, + 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, + 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, + 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, + 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, + 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, + 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, + 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, + 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, + 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, + 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, + 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 +}; +static const uint32_t table3_[256] = { + 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, + 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, + 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, + 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, + 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, + 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, + 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, + 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, + 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, + 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, + 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, + 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, + 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, + 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, + 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, + 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, + 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, + 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, + 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, + 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, + 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, + 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, + 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, + 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, + 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, + 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, + 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, + 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, + 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, + 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, + 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, + 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, + 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, + 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, + 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, + 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, + 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, + 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, + 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, + 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, + 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, + 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, + 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, + 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, + 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, + 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, + 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, + 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, + 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, + 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, + 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, + 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, + 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, + 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, + 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, + 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, + 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, + 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, + 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, + 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, + 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, + 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, + 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, + 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 +}; + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + return DecodeFixed32(reinterpret_cast(p)); +} + +uint32_t Extend(uint32_t crc, const char* buf, size_t size) { + const uint8_t *p = reinterpret_cast(buf); + const uint8_t *e = p + size; + uint32_t l = crc ^ 0xffffffffu; + +#define STEP1 do { \ + int c = (l & 0xff) ^ *p++; \ + l = table0_[c] ^ (l >> 8); \ +} while (0) +#define STEP4 do { \ + uint32_t c = l ^ LE_LOAD32(p); \ + p += 4; \ + l = table3_[c & 0xff] ^ \ + table2_[(c >> 8) & 0xff] ^ \ + table1_[(c >> 16) & 0xff] ^ \ + table0_[c >> 24]; \ +} while (0) + + // Point x at first 4-byte aligned byte in string. This might be + // just past the end of the string. + const uintptr_t pval = reinterpret_cast(p); + const uint8_t* x = reinterpret_cast(((pval + 3) >> 2) << 2); + if (x <= e) { + // Process bytes until finished or p is 4-byte aligned + while (p != x) { + STEP1; + } + } + // Process bytes 16 at a time + while ((e-p) >= 16) { + STEP4; STEP4; STEP4; STEP4; + } + // Process bytes 4 at a time + while ((e-p) >= 4) { + STEP4; + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP4 +#undef STEP1 + return l ^ 0xffffffffu; +} + +} // namespace crc32c +} // namespace leveldb diff --git a/util/crc32c.h b/util/crc32c.h new file mode 100644 index 000000000..1d7e5c075 --- /dev/null +++ b/util/crc32c.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ +#define STORAGE_LEVELDB_UTIL_CRC32C_H_ + +#include +#include + +namespace leveldb { +namespace crc32c { + +// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the +// crc32c of some string A. Extend() is often used to maintain the +// crc32c of a stream of data. +extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); + +// Return the crc32c of data[0,n-1] +inline uint32_t Value(const char* data, size_t n) { + return Extend(0, data, n); +} + +static const uint32_t kMaskDelta = 0xa282ead8ul; + +// Return a masked representation of crc. +// +// Motivation: it is problematic to compute the CRC of a string that +// contains embedded CRCs. Therefore we recommend that CRCs stored +// somewhere (e.g., in files) should be masked before being stored. +inline uint32_t Mask(uint32_t crc) { + // Rotate right by 15 bits and add a constant. + return ((crc >> 15) | (crc << 17)) + kMaskDelta; +} + +// Return the crc whose masked representation is masked_crc. +inline uint32_t Unmask(uint32_t masked_crc) { + uint32_t rot = masked_crc - kMaskDelta; + return ((rot >> 17) | (rot << 15)); +} + +} // namespace crc32c +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/util/crc32c_test.cc b/util/crc32c_test.cc new file mode 100644 index 000000000..4b957ee12 --- /dev/null +++ b/util/crc32c_test.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/crc32c.h" +#include "util/testharness.h" + +namespace leveldb { +namespace crc32c { + +class CRC { }; + +TEST(CRC, StandardResults) { + // From rfc3720 section B.4. + char buf[32]; + + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf))); + + memset(buf, 0xff, sizeof(buf)); + ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = i; + } + ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = 31 - i; + } + ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf))); + + unsigned char data[48] = { + 0x01, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x18, + 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + ASSERT_EQ(0xd9963a56, Value(reinterpret_cast(data), sizeof(data))); +} + +TEST(CRC, Values) { + ASSERT_NE(Value("a", 1), Value("foo", 3)); +} + +TEST(CRC, Extend) { + ASSERT_EQ(Value("hello world", 11), + Extend(Value("hello ", 6), "world", 5)); +} + +TEST(CRC, Mask) { + uint32_t crc = Value("foo", 3); + ASSERT_NE(crc, Mask(crc)); + ASSERT_NE(crc, Mask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc))))); +} + +} // namespace crc32c +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/env.cc b/util/env.cc new file mode 100644 index 000000000..c2600e964 --- /dev/null +++ b/util/env.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +namespace leveldb { + +Env::~Env() { +} + +SequentialFile::~SequentialFile() { +} + +RandomAccessFile::~RandomAccessFile() { +} + +WritableFile::~WritableFile() { +} + +Logger::~Logger() { +} + +FileLock::~FileLock() { +} + +void Log(Logger* info_log, const char* format, ...) { + if (info_log != NULL) { + va_list ap; + va_start(ap, format); + info_log->Logv(format, ap); + va_end(ap); + } +} + +static Status DoWriteStringToFile(Env* env, const Slice& data, + const std::string& fname, + bool should_sync) { + WritableFile* file; + Status s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + s = file->Append(data); + if (s.ok() && should_sync) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; // Will auto-close if we did not close above + if (!s.ok()) { + env->DeleteFile(fname); + } + return s; +} + +Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, false); +} + +Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, true); +} + +Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { + data->clear(); + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + static const int kBufferSize = 8192; + char* space = new char[kBufferSize]; + while (true) { + Slice fragment; + s = file->Read(kBufferSize, &fragment, space); + if (!s.ok()) { + break; + } + data->append(fragment.data(), fragment.size()); + if (fragment.empty()) { + break; + } + } + delete[] space; + delete file; + return s; +} + +EnvWrapper::~EnvWrapper() { +} + +} // namespace leveldb diff --git a/util/env_posix.cc b/util/env_posix.cc new file mode 100644 index 000000000..db81f56d1 --- /dev/null +++ b/util/env_posix.cc @@ -0,0 +1,701 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +#if !defined(LEVELDB_PLATFORM_WINDOWS) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(LEVELDB_PLATFORM_ANDROID) +#include +#endif +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/posix_logger.h" + +namespace leveldb { + +namespace { + +static Status IOError(const std::string& context, int err_number) { + return Status::IOError(context, strerror(err_number)); +} + +class PosixSequentialFile: public SequentialFile { + private: + std::string filename_; + FILE* file_; + + public: + PosixSequentialFile(const std::string& fname, FILE* f) + : filename_(fname), file_(f) { } + virtual ~PosixSequentialFile() { fclose(file_); } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s; + size_t r = fread_unlocked(scratch, 1, n, file_); + *result = Slice(scratch, r); + if (r < n) { + if (feof(file_)) { + // We leave status as ok if we hit the end of the file + } else { + // A partial read with an error: return a non-ok status + s = IOError(filename_, errno); + } + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (fseek(file_, n, SEEK_CUR)) { + return IOError(filename_, errno); + } + return Status::OK(); + } +}; + +// pread() based random-access +class PosixRandomAccessFile: public RandomAccessFile { + private: + std::string filename_; + int fd_; + + public: + PosixRandomAccessFile(const std::string& fname, int fd) + : filename_(fname), fd_(fd) { } + virtual ~PosixRandomAccessFile() { close(fd_); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + ssize_t r = pread(fd_, scratch, n, static_cast(offset)); + *result = Slice(scratch, (r < 0) ? 0 : r); + if (r < 0) { + // An error: return a non-ok status + s = IOError(filename_, errno); + } + return s; + } +}; + +// Helper class to limit mmap file usage so that we do not end up +// running out virtual memory or running into kernel performance +// problems for very large databases. +class MmapLimiter { + public: + // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. + MmapLimiter() { + SetAllowed(sizeof(void*) >= 8 ? 1000 : 0); + } + + // If another mmap slot is available, acquire it and return true. + // Else return false. + bool Acquire() { + if (GetAllowed() <= 0) { + return false; + } + MutexLock l(&mu_); + intptr_t x = GetAllowed(); + if (x <= 0) { + return false; + } else { + SetAllowed(x - 1); + return true; + } + } + + // Release a slot acquired by a previous call to Acquire() that returned true. + void Release() { + MutexLock l(&mu_); + SetAllowed(GetAllowed() + 1); + } + + private: + port::Mutex mu_; + port::AtomicPointer allowed_; + + intptr_t GetAllowed() const { + return reinterpret_cast(allowed_.Acquire_Load()); + } + + // REQUIRES: mu_ must be held + void SetAllowed(intptr_t v) { + allowed_.Release_Store(reinterpret_cast(v)); + } + + MmapLimiter(const MmapLimiter&); + void operator=(const MmapLimiter&); +}; + +// mmap() based random-access +class PosixMmapReadableFile: public RandomAccessFile { + private: + std::string filename_; + void* mmapped_region_; + size_t length_; + MmapLimiter* limiter_; + + public: + // base[0,length-1] contains the mmapped contents of the file. + PosixMmapReadableFile(const std::string& fname, void* base, size_t length, + MmapLimiter* limiter) + : filename_(fname), mmapped_region_(base), length_(length), + limiter_(limiter) { + } + + virtual ~PosixMmapReadableFile() { + munmap(mmapped_region_, length_); + limiter_->Release(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + if (offset + n > length_) { + *result = Slice(); + s = IOError(filename_, EINVAL); + } else { + *result = Slice(reinterpret_cast(mmapped_region_) + offset, n); + } + return s; + } +}; + +// We preallocate up to an extra megabyte and use memcpy to append new +// data to the file. This is safe since we either properly close the +// file before reading from it, or for log files, the reading code +// knows enough to skip zero suffixes. +class PosixMmapFile : public WritableFile { + private: + std::string filename_; + int fd_; + size_t page_size_; + size_t map_size_; // How much extra memory to map at a time + char* base_; // The mapped region + char* limit_; // Limit of the mapped region + char* dst_; // Where to write next (in range [base_,limit_]) + char* last_sync_; // Where have we synced up to + uint64_t file_offset_; // Offset of base_ in file + + // Have we done an munmap of unsynced data? + bool pending_sync_; + + // Roundup x to a multiple of y + static size_t Roundup(size_t x, size_t y) { + return ((x + y - 1) / y) * y; + } + + size_t TruncateToPageBoundary(size_t s) { + s -= (s & (page_size_ - 1)); + assert((s % page_size_) == 0); + return s; + } + + bool UnmapCurrentRegion() { + bool result = true; + if (base_ != NULL) { + if (last_sync_ < limit_) { + // Defer syncing this data until next Sync() call, if any + pending_sync_ = true; + } + if (munmap(base_, limit_ - base_) != 0) { + result = false; + } + file_offset_ += limit_ - base_; + base_ = NULL; + limit_ = NULL; + last_sync_ = NULL; + dst_ = NULL; + + // Increase the amount we map the next time, but capped at 1MB + if (map_size_ < (1<<20)) { + map_size_ *= 2; + } + } + return result; + } + + bool MapNewRegion() { + assert(base_ == NULL); + if (ftruncate(fd_, file_offset_ + map_size_) < 0) { + return false; + } + void* ptr = mmap(NULL, map_size_, PROT_READ | PROT_WRITE, MAP_SHARED, + fd_, file_offset_); + if (ptr == MAP_FAILED) { + return false; + } + base_ = reinterpret_cast(ptr); + limit_ = base_ + map_size_; + dst_ = base_; + last_sync_ = base_; + return true; + } + + public: + PosixMmapFile(const std::string& fname, int fd, size_t page_size) + : filename_(fname), + fd_(fd), + page_size_(page_size), + map_size_(Roundup(65536, page_size)), + base_(NULL), + limit_(NULL), + dst_(NULL), + last_sync_(NULL), + file_offset_(0), + pending_sync_(false) { + assert((page_size & (page_size - 1)) == 0); + } + + + ~PosixMmapFile() { + if (fd_ >= 0) { + PosixMmapFile::Close(); + } + } + + virtual Status Append(const Slice& data) { + const char* src = data.data(); + size_t left = data.size(); + while (left > 0) { + assert(base_ <= dst_); + assert(dst_ <= limit_); + size_t avail = limit_ - dst_; + if (avail == 0) { + if (!UnmapCurrentRegion() || + !MapNewRegion()) { + return IOError(filename_, errno); + } + } + + size_t n = (left <= avail) ? left : avail; + memcpy(dst_, src, n); + dst_ += n; + src += n; + left -= n; + } + return Status::OK(); + } + + virtual Status Close() { + Status s; + size_t unused = limit_ - dst_; + if (!UnmapCurrentRegion()) { + s = IOError(filename_, errno); + } else if (unused > 0) { + // Trim the extra space at the end of the file + if (ftruncate(fd_, file_offset_ - unused) < 0) { + s = IOError(filename_, errno); + } + } + + if (close(fd_) < 0) { + if (s.ok()) { + s = IOError(filename_, errno); + } + } + + fd_ = -1; + base_ = NULL; + limit_ = NULL; + return s; + } + + virtual Status Flush() { + return Status::OK(); + } + + virtual Status Sync() { + Status s; + + if (pending_sync_) { + // Some unmapped data was not synced + pending_sync_ = false; + if (fdatasync(fd_) < 0) { + s = IOError(filename_, errno); + } + } + + if (dst_ > last_sync_) { + // Find the beginnings of the pages that contain the first and last + // bytes to be synced. + size_t p1 = TruncateToPageBoundary(last_sync_ - base_); + size_t p2 = TruncateToPageBoundary(dst_ - base_ - 1); + last_sync_ = dst_; + if (msync(base_ + p1, p2 - p1 + page_size_, MS_SYNC) < 0) { + s = IOError(filename_, errno); + } + } + + return s; + } +}; + +static int LockOrUnlock(int fd, bool lock) { + errno = 0; + struct flock f; + memset(&f, 0, sizeof(f)); + f.l_type = (lock ? F_WRLCK : F_UNLCK); + f.l_whence = SEEK_SET; + f.l_start = 0; + f.l_len = 0; // Lock/unlock entire file + return fcntl(fd, F_SETLK, &f); +} + +class PosixFileLock : public FileLock { + public: + int fd_; + std::string name_; +}; + +// Set of locked files. We keep a separate set instead of just +// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide +// any protection against multiple uses from the same process. +class PosixLockTable { + private: + port::Mutex mu_; + std::set locked_files_; + public: + bool Insert(const std::string& fname) { + MutexLock l(&mu_); + return locked_files_.insert(fname).second; + } + void Remove(const std::string& fname) { + MutexLock l(&mu_); + locked_files_.erase(fname); + } +}; + +class PosixEnv : public Env { + public: + PosixEnv(); + virtual ~PosixEnv() { + fprintf(stderr, "Destroying Env::Default()\n"); + exit(1); + } + + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + FILE* f = fopen(fname.c_str(), "r"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixSequentialFile(fname, f); + return Status::OK(); + } + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + *result = NULL; + Status s; + int fd = open(fname.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(fname, errno); + } else if (mmap_limit_.Acquire()) { + uint64_t size; + s = GetFileSize(fname, &size); + if (s.ok()) { + void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (base != MAP_FAILED) { + *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_); + } else { + s = IOError(fname, errno); + } + } + close(fd); + if (!s.ok()) { + mmap_limit_.Release(); + } + } else { + *result = new PosixRandomAccessFile(fname, fd); + } + return s; + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + Status s; + const int fd = open(fname.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644); + if (fd < 0) { + *result = NULL; + s = IOError(fname, errno); + } else { + *result = new PosixMmapFile(fname, fd, page_size_); + } + return s; + } + + virtual bool FileExists(const std::string& fname) { + return access(fname.c_str(), F_OK) == 0; + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + result->clear(); + DIR* d = opendir(dir.c_str()); + if (d == NULL) { + return IOError(dir, errno); + } + struct dirent* entry; + while ((entry = readdir(d)) != NULL) { + result->push_back(entry->d_name); + } + closedir(d); + return Status::OK(); + } + + virtual Status DeleteFile(const std::string& fname) { + Status result; + if (unlink(fname.c_str()) != 0) { + result = IOError(fname, errno); + } + return result; + }; + + virtual Status CreateDir(const std::string& name) { + Status result; + if (mkdir(name.c_str(), 0755) != 0) { + result = IOError(name, errno); + } + return result; + }; + + virtual Status DeleteDir(const std::string& name) { + Status result; + if (rmdir(name.c_str()) != 0) { + result = IOError(name, errno); + } + return result; + }; + + virtual Status GetFileSize(const std::string& fname, uint64_t* size) { + Status s; + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + *size = 0; + s = IOError(fname, errno); + } else { + *size = sbuf.st_size; + } + return s; + } + + virtual Status RenameFile(const std::string& src, const std::string& target) { + Status result; + if (rename(src.c_str(), target.c_str()) != 0) { + result = IOError(src, errno); + } + return result; + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = NULL; + Status result; + int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644); + if (fd < 0) { + result = IOError(fname, errno); + } else if (!locks_.Insert(fname)) { + close(fd); + result = Status::IOError("lock " + fname, "already held by process"); + } else if (LockOrUnlock(fd, true) == -1) { + result = IOError("lock " + fname, errno); + close(fd); + locks_.Remove(fname); + } else { + PosixFileLock* my_lock = new PosixFileLock; + my_lock->fd_ = fd; + my_lock->name_ = fname; + *lock = my_lock; + } + return result; + } + + virtual Status UnlockFile(FileLock* lock) { + PosixFileLock* my_lock = reinterpret_cast(lock); + Status result; + if (LockOrUnlock(my_lock->fd_, false) == -1) { + result = IOError("unlock", errno); + } + locks_.Remove(my_lock->name_); + close(my_lock->fd_); + delete my_lock; + return result; + } + + virtual void Schedule(void (*function)(void*), void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* result) { + const char* env = getenv("TEST_TMPDIR"); + if (env && env[0] != '\0') { + *result = env; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); + *result = buf; + } + // Directory may already exist + CreateDir(*result); + return Status::OK(); + } + + static uint64_t gettid() { + pthread_t tid = pthread_self(); + uint64_t thread_id = 0; + memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); + return thread_id; + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + FILE* f = fopen(fname.c_str(), "w"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixLogger(f, &PosixEnv::gettid); + return Status::OK(); + } + } + + virtual uint64_t NowMicros() { + struct timeval tv; + gettimeofday(&tv, NULL); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + } + + virtual void SleepForMicroseconds(int micros) { + usleep(micros); + } + + private: + void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + exit(1); + } + } + + // BGThread() is the body of the background thread + void BGThread(); + static void* BGThreadWrapper(void* arg) { + reinterpret_cast(arg)->BGThread(); + return NULL; + } + + size_t page_size_; + pthread_mutex_t mu_; + pthread_cond_t bgsignal_; + pthread_t bgthread_; + bool started_bgthread_; + + // Entry per Schedule() call + struct BGItem { void* arg; void (*function)(void*); }; + typedef std::deque BGQueue; + BGQueue queue_; + + PosixLockTable locks_; + MmapLimiter mmap_limit_; +}; + +PosixEnv::PosixEnv() : page_size_(getpagesize()), + started_bgthread_(false) { + PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); + PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); +} + +void PosixEnv::Schedule(void (*function)(void*), void* arg) { + PthreadCall("lock", pthread_mutex_lock(&mu_)); + + // Start background thread if necessary + if (!started_bgthread_) { + started_bgthread_ = true; + PthreadCall( + "create thread", + pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this)); + } + + // If the queue is currently empty, the background thread may currently be + // waiting. + if (queue_.empty()) { + PthreadCall("signal", pthread_cond_signal(&bgsignal_)); + } + + // Add to priority queue + queue_.push_back(BGItem()); + queue_.back().function = function; + queue_.back().arg = arg; + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); +} + +void PosixEnv::BGThread() { + while (true) { + // Wait until there is an item that is ready to run + PthreadCall("lock", pthread_mutex_lock(&mu_)); + while (queue_.empty()) { + PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_)); + } + + void (*function)(void*) = queue_.front().function; + void* arg = queue_.front().arg; + queue_.pop_front(); + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); + (*function)(arg); + } +} + +namespace { +struct StartThreadState { + void (*user_function)(void*); + void* arg; +}; +} +static void* StartThreadWrapper(void* arg) { + StartThreadState* state = reinterpret_cast(arg); + state->user_function(state->arg); + delete state; + return NULL; +} + +void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { + pthread_t t; + StartThreadState* state = new StartThreadState; + state->user_function = function; + state->arg = arg; + PthreadCall("start thread", + pthread_create(&t, NULL, &StartThreadWrapper, state)); +} + +} // namespace + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new PosixEnv; } + +Env* Env::Default() { + pthread_once(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#endif diff --git a/util/env_test.cc b/util/env_test.cc new file mode 100644 index 000000000..b72cb4438 --- /dev/null +++ b/util/env_test.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +#include "port/port.h" +#include "util/testharness.h" + +namespace leveldb { + +static const int kDelayMicros = 100000; + +class EnvPosixTest { + private: + port::Mutex mu_; + std::string events_; + + public: + Env* env_; + EnvPosixTest() : env_(Env::Default()) { } +}; + +static void SetBool(void* ptr) { + reinterpret_cast(ptr)->NoBarrier_Store(ptr); +} + +TEST(EnvPosixTest, RunImmediately) { + port::AtomicPointer called (NULL); + env_->Schedule(&SetBool, &called); + Env::Default()->SleepForMicroseconds(kDelayMicros); + ASSERT_TRUE(called.NoBarrier_Load() != NULL); +} + +TEST(EnvPosixTest, RunMany) { + port::AtomicPointer last_id (NULL); + + struct CB { + port::AtomicPointer* last_id_ptr; // Pointer to shared slot + uintptr_t id; // Order# for the execution of this callback + + CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } + + static void Run(void* v) { + CB* cb = reinterpret_cast(v); + void* cur = cb->last_id_ptr->NoBarrier_Load(); + ASSERT_EQ(cb->id-1, reinterpret_cast(cur)); + cb->last_id_ptr->Release_Store(reinterpret_cast(cb->id)); + } + }; + + // Schedule in different order than start time + CB cb1(&last_id, 1); + CB cb2(&last_id, 2); + CB cb3(&last_id, 3); + CB cb4(&last_id, 4); + env_->Schedule(&CB::Run, &cb1); + env_->Schedule(&CB::Run, &cb2); + env_->Schedule(&CB::Run, &cb3); + env_->Schedule(&CB::Run, &cb4); + + Env::Default()->SleepForMicroseconds(kDelayMicros); + void* cur = last_id.Acquire_Load(); + ASSERT_EQ(4, reinterpret_cast(cur)); +} + +struct State { + port::Mutex mu; + int val; + int num_running; +}; + +static void ThreadBody(void* arg) { + State* s = reinterpret_cast(arg); + s->mu.Lock(); + s->val += 1; + s->num_running -= 1; + s->mu.Unlock(); +} + +TEST(EnvPosixTest, StartThread) { + State state; + state.val = 0; + state.num_running = 3; + for (int i = 0; i < 3; i++) { + env_->StartThread(&ThreadBody, &state); + } + while (true) { + state.mu.Lock(); + int num = state.num_running; + state.mu.Unlock(); + if (num == 0) { + break; + } + Env::Default()->SleepForMicroseconds(kDelayMicros); + } + ASSERT_EQ(state.val, 3); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/env_win.cc b/util/env_win.cc new file mode 100644 index 000000000..ef2ecae83 --- /dev/null +++ b/util/env_win.cc @@ -0,0 +1,1031 @@ +// This file contains source that originates from: +// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h +// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc +// Those files dont' have any explict license headers but the +// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' +// as the license. +#if defined(LEVELDB_PLATFORM_WINDOWS) +#include + + +#include "leveldb/env.h" + +#include "port/port.h" +#include "leveldb/slice.h" +#include "util/logging.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef max +#undef max +#endif + +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +#if defined DeleteFile +#undef DeleteFile +#endif + +//Declarations +namespace leveldb +{ + +namespace Win32 +{ + +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +std::string GetCurrentDir(); +std::wstring GetCurrentDirW(); + +static const std::string CurrentDir = GetCurrentDir(); +static const std::wstring CurrentDirW = GetCurrentDirW(); + +std::string& ModifyPath(std::string& path); +std::wstring& ModifyPath(std::wstring& path); + +std::string GetLastErrSz(); +std::wstring GetLastErrSzW(); + +size_t GetPageSize(); + +typedef void (*ScheduleProc)(void*) ; + +struct WorkItemWrapper +{ + WorkItemWrapper(ScheduleProc proc_,void* content_); + ScheduleProc proc; + void* pContent; +}; + +DWORD WINAPI WorkItemWrapperProc(LPVOID pContent); + +class Win32SequentialFile : public SequentialFile +{ +public: + friend class Win32Env; + virtual ~Win32SequentialFile(); + virtual Status Read(size_t n, Slice* result, char* scratch); + virtual Status Skip(uint64_t n); + BOOL isEnable(); +private: + BOOL _Init(); + void _CleanUp(); + Win32SequentialFile(const std::string& fname); + std::string _filename; + ::HANDLE _hFile; + DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile); +}; + +class Win32RandomAccessFile : public RandomAccessFile +{ +public: + friend class Win32Env; + virtual ~Win32RandomAccessFile(); + virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; + BOOL isEnable(); +private: + BOOL _Init(LPCWSTR path); + void _CleanUp(); + Win32RandomAccessFile(const std::string& fname); + HANDLE _hFile; + const std::string _filename; + DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); +}; + +class Win32MapFile : public WritableFile +{ +public: + Win32MapFile(const std::string& fname); + + ~Win32MapFile(); + virtual Status Append(const Slice& data); + virtual Status Close(); + virtual Status Flush(); + virtual Status Sync(); + BOOL isEnable(); +private: + std::string _filename; + HANDLE _hFile; + size_t _page_size; + size_t _map_size; // How much extra memory to map at a time + char* _base; // The mapped region + HANDLE _base_handle; + char* _limit; // Limit of the mapped region + char* _dst; // Where to write next (in range [base_,limit_]) + char* _last_sync; // Where have we synced up to + uint64_t _file_offset; // Offset of base_ in file + //LARGE_INTEGER file_offset_; + // Have we done an munmap of unsynced data? + bool _pending_sync; + + // Roundup x to a multiple of y + static size_t _Roundup(size_t x, size_t y); + size_t _TruncateToPageBoundary(size_t s); + bool _UnmapCurrentRegion(); + bool _MapNewRegion(); + DISALLOW_COPY_AND_ASSIGN(Win32MapFile); + BOOL _Init(LPCWSTR Path); +}; + +class Win32FileLock : public FileLock +{ +public: + friend class Win32Env; + virtual ~Win32FileLock(); + BOOL isEnable(); +private: + BOOL _Init(LPCWSTR path); + void _CleanUp(); + Win32FileLock(const std::string& fname); + HANDLE _hFile; + std::string _filename; + DISALLOW_COPY_AND_ASSIGN(Win32FileLock); +}; + +class Win32Logger : public Logger +{ +public: + friend class Win32Env; + virtual ~Win32Logger(); + virtual void Logv(const char* format, va_list ap); +private: + explicit Win32Logger(WritableFile* pFile); + WritableFile* _pFileProxy; + DISALLOW_COPY_AND_ASSIGN(Win32Logger); +}; + +class Win32Env : public Env +{ +public: + Win32Env(); + virtual ~Win32Env(); + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result); + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result); + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result); + + virtual bool FileExists(const std::string& fname); + + virtual Status GetChildren(const std::string& dir, + std::vector* result); + + virtual Status DeleteFile(const std::string& fname); + + virtual Status CreateDir(const std::string& dirname); + + virtual Status DeleteDir(const std::string& dirname); + + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size); + + virtual Status RenameFile(const std::string& src, + const std::string& target); + + virtual Status LockFile(const std::string& fname, FileLock** lock); + + virtual Status UnlockFile(FileLock* lock); + + virtual void Schedule( + void (*function)(void* arg), + void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* path); + + //virtual void Logv(WritableFile* log, const char* format, va_list ap); + + virtual Status NewLogger(const std::string& fname, Logger** result); + + virtual uint64_t NowMicros(); + + virtual void SleepForMicroseconds(int micros); +}; + +void ToWidePath(const std::string& value, std::wstring& target) { + wchar_t buffer[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); + target = buffer; +} + +void ToNarrowPath(const std::wstring& value, std::string& target) { + char buffer[MAX_PATH]; + WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); + target = buffer; +} + +std::string GetCurrentDir() +{ + CHAR path[MAX_PATH]; + ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); + *strrchr(path,'\\') = 0; + return std::string(path); +} + +std::wstring GetCurrentDirW() +{ + WCHAR path[MAX_PATH]; + ::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH); + *wcsrchr(path,L'\\') = 0; + return std::wstring(path); +} + +std::string& ModifyPath(std::string& path) +{ + if(path[0] == '/' || path[0] == '\\'){ + path = CurrentDir + path; + } + std::replace(path.begin(),path.end(),'/','\\'); + + return path; +} + +std::wstring& ModifyPath(std::wstring& path) +{ + if(path[0] == L'/' || path[0] == L'\\'){ + path = CurrentDirW + path; + } + std::replace(path.begin(),path.end(),L'/',L'\\'); + return path; +} + +std::string GetLastErrSz() +{ + LPWSTR lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + std::string Err; + ToNarrowPath(lpMsgBuf, Err); + LocalFree( lpMsgBuf ); + return Err; +} + +std::wstring GetLastErrSzW() +{ + LPVOID lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + std::wstring Err = (LPCWSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + return Err; +} + +WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) : + proc(proc_),pContent(content_) +{ + +} + +DWORD WINAPI WorkItemWrapperProc(LPVOID pContent) +{ + WorkItemWrapper* item = static_cast(pContent); + ScheduleProc TempProc = item->proc; + void* arg = item->pContent; + delete item; + TempProc(arg); + return 0; +} + +size_t GetPageSize() +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return std::max(si.dwPageSize,si.dwAllocationGranularity); +} + +const size_t g_PageSize = GetPageSize(); + + +Win32SequentialFile::Win32SequentialFile( const std::string& fname ) : + _filename(fname),_hFile(NULL) +{ + _Init(); +} + +Win32SequentialFile::~Win32SequentialFile() +{ + _CleanUp(); +} + +Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch ) +{ + Status sRet; + DWORD hasRead = 0; + if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){ + *result = Slice(scratch,hasRead); + } else { + sRet = Status::IOError(_filename, Win32::GetLastErrSz() ); + } + return sRet; +} + +Status Win32SequentialFile::Skip( uint64_t n ) +{ + Status sRet; + LARGE_INTEGER Move,NowPointer; + Move.QuadPart = n; + if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){ + sRet = Status::IOError(_filename,Win32::GetLastErrSz()); + } + return sRet; +} + +BOOL Win32SequentialFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +BOOL Win32SequentialFile::_Init() +{ + std::wstring path; + ToWidePath(_filename, path); + _hFile = CreateFileW(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + return _hFile ? TRUE : FALSE; +} + +void Win32SequentialFile::_CleanUp() +{ + if(_hFile){ + CloseHandle(_hFile); + _hFile = NULL; + } +} + +Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) : + _filename(fname),_hFile(NULL) +{ + std::wstring path; + ToWidePath(fname, path); + _Init( path.c_str() ); +} + +Win32RandomAccessFile::~Win32RandomAccessFile() +{ + _CleanUp(); +} + +Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const +{ + Status sRet; + OVERLAPPED ol = {0}; + ZeroMemory(&ol,sizeof(ol)); + ol.Offset = (DWORD)offset; + ol.OffsetHigh = (DWORD)(offset >> 32); + DWORD hasRead = 0; + if(!ReadFile(_hFile,scratch,n,&hasRead,&ol)) + sRet = Status::IOError(_filename,Win32::GetLastErrSz()); + else + *result = Slice(scratch,hasRead); + return sRet; +} + +BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) +{ + BOOL bRet = FALSE; + if(!_hFile) + _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) + _hFile = NULL; + else + bRet = TRUE; + return bRet; +} + +BOOL Win32RandomAccessFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +void Win32RandomAccessFile::_CleanUp() +{ + if(_hFile){ + ::CloseHandle(_hFile); + _hFile = NULL; + } +} + +size_t Win32MapFile::_Roundup( size_t x, size_t y ) +{ + return ((x + y - 1) / y) * y; +} + +size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) +{ + s -= (s & (_page_size - 1)); + assert((s % _page_size) == 0); + return s; +} + +bool Win32MapFile::_UnmapCurrentRegion() +{ + bool result = true; + if (_base != NULL) { + if (_last_sync < _limit) { + // Defer syncing this data until next Sync() call, if any + _pending_sync = true; + } + if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) + result = false; + _file_offset += _limit - _base; + _base = NULL; + _base_handle = NULL; + _limit = NULL; + _last_sync = NULL; + _dst = NULL; + // Increase the amount we map the next time, but capped at 1MB + if (_map_size < (1<<20)) { + _map_size *= 2; + } + } + return result; +} + +bool Win32MapFile::_MapNewRegion() +{ + assert(_base == NULL); + //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); + //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); + DWORD off_hi = (DWORD)(_file_offset >> 32); + DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); + LARGE_INTEGER newSize; + newSize.QuadPart = _file_offset + _map_size; + SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); + SetEndOfFile(_hFile); + + _base_handle = CreateFileMappingA( + _hFile, + NULL, + PAGE_READWRITE, + 0, + 0, + 0); + if (_base_handle != NULL) { + _base = (char*) MapViewOfFile(_base_handle, + FILE_MAP_ALL_ACCESS, + off_hi, + off_lo, + _map_size); + if (_base != NULL) { + _limit = _base + _map_size; + _dst = _base; + _last_sync = _base; + return true; + } + } + return false; +} + +Win32MapFile::Win32MapFile( const std::string& fname) : + _filename(fname), + _hFile(NULL), + _page_size(Win32::g_PageSize), + _map_size(_Roundup(65536, Win32::g_PageSize)), + _base(NULL), + _base_handle(NULL), + _limit(NULL), + _dst(NULL), + _last_sync(NULL), + _file_offset(0), + _pending_sync(false) +{ + std::wstring path; + ToWidePath(fname, path); + _Init(path.c_str()); + assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); +} + +Status Win32MapFile::Append( const Slice& data ) +{ + const char* src = data.data(); + size_t left = data.size(); + Status s; + while (left > 0) { + assert(_base <= _dst); + assert(_dst <= _limit); + size_t avail = _limit - _dst; + if (avail == 0) { + if (!_UnmapCurrentRegion() || + !_MapNewRegion()) { + return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); + } + } + size_t n = (left <= avail) ? left : avail; + memcpy(_dst, src, n); + _dst += n; + src += n; + left -= n; + } + return s; +} + +Status Win32MapFile::Close() +{ + Status s; + size_t unused = _limit - _dst; + if (!_UnmapCurrentRegion()) { + s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); + } else if (unused > 0) { + // Trim the extra space at the end of the file + LARGE_INTEGER newSize; + newSize.QuadPart = _file_offset - unused; + if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { + s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); + } else + SetEndOfFile(_hFile); + } + if (!CloseHandle(_hFile)) { + if (s.ok()) { + s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); + } + } + _hFile = INVALID_HANDLE_VALUE; + _base = NULL; + _base_handle = NULL; + _limit = NULL; + + return s; +} + +Status Win32MapFile::Sync() +{ + Status s; + if (_pending_sync) { + // Some unmapped data was not synced + _pending_sync = false; + if (!FlushFileBuffers(_hFile)) { + s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); + } + } + if (_dst > _last_sync) { + // Find the beginnings of the pages that contain the first and last + // bytes to be synced. + size_t p1 = _TruncateToPageBoundary(_last_sync - _base); + size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); + _last_sync = _dst; + if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { + s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); + } + } + return s; +} + +Status Win32MapFile::Flush() +{ + return Status::OK(); +} + +Win32MapFile::~Win32MapFile() +{ + if (_hFile != INVALID_HANDLE_VALUE) { + Win32MapFile::Close(); + } +} + +BOOL Win32MapFile::_Init( LPCWSTR Path ) +{ + DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; + _hFile = CreateFileW(Path, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, + NULL, + Flag, + FILE_ATTRIBUTE_NORMAL, + NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE) + return FALSE; + else + return TRUE; +} + +BOOL Win32MapFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +Win32FileLock::Win32FileLock( const std::string& fname ) : + _hFile(NULL),_filename(fname) +{ + std::wstring path; + ToWidePath(fname, path); + _Init(path.c_str()); +} + +Win32FileLock::~Win32FileLock() +{ + _CleanUp(); +} + +BOOL Win32FileLock::_Init( LPCWSTR path ) +{ + BOOL bRet = FALSE; + if(!_hFile) + _hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){ + _hFile = NULL; + } + else + bRet = TRUE; + return bRet; +} + +void Win32FileLock::_CleanUp() +{ + ::CloseHandle(_hFile); + _hFile = NULL; +} + +BOOL Win32FileLock::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile) +{ + assert(_pFileProxy); +} + +Win32Logger::~Win32Logger() +{ + if(_pFileProxy) + delete _pFileProxy; +} + +void Win32Logger::Logv( const char* format, va_list ap ) +{ + uint64_t thread_id = ::GetCurrentThreadId(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + char buffer[500]; + for (int iter = 0; iter < 2; iter++) { + char* base; + int bufsize; + if (iter == 0) { + bufsize = sizeof(buffer); + base = buffer; + } else { + bufsize = 30000; + base = new char[bufsize]; + } + char* p = base; + char* limit = base + bufsize; + + SYSTEMTIME st; + GetLocalTime(&st); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + int(st.wYear), + int(st.wMonth), + int(st.wDay), + int(st.wHour), + int(st.wMinute), + int(st.wMinute), + int(st.wMilliseconds), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + p += vsnprintf(p, limit - p, format, backup_ap); + va_end(backup_ap); + } + + // Truncate to available space if necessary + if (p >= limit) { + if (iter == 0) { + continue; // Try again with larger buffer + } else { + p = limit - 1; + } + } + + // Add newline if necessary + if (p == base || p[-1] != '\n') { + *p++ = '\n'; + } + + assert(p <= limit); + DWORD hasWritten = 0; + if(_pFileProxy){ + _pFileProxy->Append(Slice(base, p - base)); + _pFileProxy->Flush(); + } + if (base != buffer) { + delete[] base; + } + break; + } +} + +bool Win32Env::FileExists(const std::string& fname) +{ + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + return ::PathFileExistsW(wpath.c_str()) ? true : false; +} + +Status Win32Env::GetChildren(const std::string& dir, std::vector* result) +{ + Status sRet; + ::WIN32_FIND_DATAW wfd; + std::string path = dir; + ModifyPath(path); + path += "\\*.*"; + std::wstring wpath; + ToWidePath(path, wpath); + + ::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd); + if(hFind && hFind != INVALID_HANDLE_VALUE){ + BOOL hasNext = TRUE; + std::string child; + while(hasNext){ + ToNarrowPath(wfd.cFileName, child); + if(child != ".." && child != ".") { + result->push_back(child); + } + hasNext = ::FindNextFileW(hFind,&wfd); + } + ::FindClose(hFind); + } + else + sRet = Status::IOError(dir,"Could not get children."); + return sRet; +} + +void Win32Env::SleepForMicroseconds( int micros ) +{ + ::Sleep((micros + 999) /1000); +} + + +Status Win32Env::DeleteFile( const std::string& fname ) +{ + Status sRet; + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + + if(!::DeleteFileW(wpath.c_str())) { + sRet = Status::IOError(path, "Could not delete file."); + } + return sRet; +} + +Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) +{ + Status sRet; + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + + HANDLE file = ::CreateFileW(wpath.c_str(), + GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + LARGE_INTEGER li; + if(::GetFileSizeEx(file,&li)){ + *file_size = (uint64_t)li.QuadPart; + }else + sRet = Status::IOError(path,"Could not get the file size."); + CloseHandle(file); + return sRet; +} + +Status Win32Env::RenameFile( const std::string& src, const std::string& target ) +{ + Status sRet; + std::string src_path = src; + std::wstring wsrc_path; + ToWidePath(ModifyPath(src_path), wsrc_path); + std::string target_path = target; + std::wstring wtarget_path; + ToWidePath(ModifyPath(target_path), wtarget_path); + + if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){ + DWORD err = GetLastError(); + if(err == 0x000000b7){ + if(!::DeleteFileW(wtarget_path.c_str() ) ) + sRet = Status::IOError(src, "Could not rename file."); + else if(!::MoveFileW(wsrc_path.c_str(), + wtarget_path.c_str() ) ) + sRet = Status::IOError(src, "Could not rename file."); + } + } + return sRet; +} + +Status Win32Env::LockFile( const std::string& fname, FileLock** lock ) +{ + Status sRet; + std::string path = fname; + ModifyPath(path); + Win32FileLock* _lock = new Win32FileLock(path); + if(!_lock->isEnable()){ + delete _lock; + *lock = NULL; + sRet = Status::IOError(path, "Could not lock file."); + } + else + *lock = _lock; + return sRet; +} + +Status Win32Env::UnlockFile( FileLock* lock ) +{ + Status sRet; + delete lock; + return sRet; +} + +void Win32Env::Schedule( void (*function)(void* arg), void* arg ) +{ + QueueUserWorkItem(Win32::WorkItemWrapperProc, + new Win32::WorkItemWrapper(function,arg), + WT_EXECUTEDEFAULT); +} + +void Win32Env::StartThread( void (*function)(void* arg), void* arg ) +{ + ::_beginthread(function,0,arg); +} + +Status Win32Env::GetTestDirectory( std::string* path ) +{ + Status sRet; + WCHAR TempPath[MAX_PATH]; + ::GetTempPathW(MAX_PATH,TempPath); + ToNarrowPath(TempPath, *path); + path->append("leveldb\\test\\"); + ModifyPath(*path); + return sRet; +} + +uint64_t Win32Env::NowMicros() +{ +#ifndef USE_VISTA_API +#define GetTickCount64 GetTickCount +#endif + return (uint64_t)(GetTickCount64()*1000); +} + +static Status CreateDirInner( const std::string& dirname ) +{ + Status sRet; + DWORD attr = ::GetFileAttributes(dirname.c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: + std::size_t slash = dirname.find_last_of("\\"); + if (slash != std::string::npos){ + sRet = CreateDirInner(dirname.substr(0, slash)); + if (!sRet.ok()) return sRet; + } + BOOL result = ::CreateDirectory(dirname.c_str(), NULL); + if (result == FALSE) { + sRet = Status::IOError(dirname, "Could not create directory."); + return sRet; + } + } + return sRet; +} + +Status Win32Env::CreateDir( const std::string& dirname ) +{ + std::string path = dirname; + if(path[path.length() - 1] != '\\'){ + path += '\\'; + } + ModifyPath(path); + + return CreateDirInner(path); +} + +Status Win32Env::DeleteDir( const std::string& dirname ) +{ + Status sRet; + std::wstring path; + ToWidePath(dirname, path); + ModifyPath(path); + if(!::RemoveDirectoryW( path.c_str() ) ){ + sRet = Status::IOError(dirname, "Could not delete directory."); + } + return sRet; +} + +Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result ) +{ + Status sRet; + std::string path = fname; + ModifyPath(path); + Win32SequentialFile* pFile = new Win32SequentialFile(path); + if(pFile->isEnable()){ + *result = pFile; + }else { + delete pFile; + sRet = Status::IOError(path, Win32::GetLastErrSz()); + } + return sRet; +} + +Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result ) +{ + Status sRet; + std::string path = fname; + Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path)); + if(!pFile->isEnable()){ + delete pFile; + *result = NULL; + sRet = Status::IOError(path, Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Status Win32Env::NewLogger( const std::string& fname, Logger** result ) +{ + Status sRet; + std::string path = fname; + Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); + if(!pMapFile->isEnable()){ + delete pMapFile; + *result = NULL; + sRet = Status::IOError(path,"could not create a logger."); + }else + *result = new Win32Logger(pMapFile); + return sRet; +} + +Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result ) +{ + Status sRet; + std::string path = fname; + Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); + if(!pFile->isEnable()){ + *result = NULL; + sRet = Status::IOError(fname,Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Win32Env::Win32Env() +{ + +} + +Win32Env::~Win32Env() +{ + +} + + +} // Win32 namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new Win32::Win32Env(); } + +Env* Env::Default() { + port::InitOnce(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#endif // defined(LEVELDB_PLATFORM_WINDOWS) diff --git a/util/filter_policy.cc b/util/filter_policy.cc new file mode 100644 index 000000000..7b045c8c9 --- /dev/null +++ b/util/filter_policy.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +namespace leveldb { + +FilterPolicy::~FilterPolicy() { } + +} // namespace leveldb diff --git a/util/hash.cc b/util/hash.cc new file mode 100644 index 000000000..ba1818082 --- /dev/null +++ b/util/hash.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "util/coding.h" +#include "util/hash.h" + +namespace leveldb { + +uint32_t Hash(const char* data, size_t n, uint32_t seed) { + // Similar to murmur hash + const uint32_t m = 0xc6a4a793; + const uint32_t r = 24; + const char* limit = data + n; + uint32_t h = seed ^ (n * m); + + // Pick up four bytes at a time + while (data + 4 <= limit) { + uint32_t w = DecodeFixed32(data); + data += 4; + h += w; + h *= m; + h ^= (h >> 16); + } + + // Pick up remaining bytes + switch (limit - data) { + case 3: + h += data[2] << 16; + // fall through + case 2: + h += data[1] << 8; + // fall through + case 1: + h += data[0]; + h *= m; + h ^= (h >> r); + break; + } + return h; +} + + +} // namespace leveldb diff --git a/util/hash.h b/util/hash.h new file mode 100644 index 000000000..8889d56be --- /dev/null +++ b/util/hash.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Simple hash function used for internal data structures + +#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ +#define STORAGE_LEVELDB_UTIL_HASH_H_ + +#include +#include + +namespace leveldb { + +extern uint32_t Hash(const char* data, size_t n, uint32_t seed); + +} + +#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/util/histogram.cc b/util/histogram.cc new file mode 100644 index 000000000..bb95f583e --- /dev/null +++ b/util/histogram.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "port/port.h" +#include "util/histogram.h" + +namespace leveldb { + +const double Histogram::kBucketLimit[kNumBuckets] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, + 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450, + 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, + 16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000, + 70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000, + 250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000, + 900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000, + 3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000, + 9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000, + 25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000, + 70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000, + 180000000, 200000000, 250000000, 300000000, 350000000, 400000000, + 450000000, 500000000, 600000000, 700000000, 800000000, 900000000, + 1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000, + 2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0, + 5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0, + 1e200, +}; + +void Histogram::Clear() { + min_ = kBucketLimit[kNumBuckets-1]; + max_ = 0; + num_ = 0; + sum_ = 0; + sum_squares_ = 0; + for (int i = 0; i < kNumBuckets; i++) { + buckets_[i] = 0; + } +} + +void Histogram::Add(double value) { + // Linear search is fast enough for our usage in db_bench + int b = 0; + while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { + b++; + } + buckets_[b] += 1.0; + if (min_ > value) min_ = value; + if (max_ < value) max_ = value; + num_++; + sum_ += value; + sum_squares_ += (value * value); +} + +void Histogram::Merge(const Histogram& other) { + if (other.min_ < min_) min_ = other.min_; + if (other.max_ > max_) max_ = other.max_; + num_ += other.num_; + sum_ += other.sum_; + sum_squares_ += other.sum_squares_; + for (int b = 0; b < kNumBuckets; b++) { + buckets_[b] += other.buckets_[b]; + } +} + +double Histogram::Median() const { + return Percentile(50.0); +} + +double Histogram::Percentile(double p) const { + double threshold = num_ * (p / 100.0); + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + sum += buckets_[b]; + if (sum >= threshold) { + // Scale linearly within this bucket + double left_point = (b == 0) ? 0 : kBucketLimit[b-1]; + double right_point = kBucketLimit[b]; + double left_sum = sum - buckets_[b]; + double right_sum = sum; + double pos = (threshold - left_sum) / (right_sum - left_sum); + double r = left_point + (right_point - left_point) * pos; + if (r < min_) r = min_; + if (r > max_) r = max_; + return r; + } + } + return max_; +} + +double Histogram::Average() const { + if (num_ == 0.0) return 0; + return sum_ / num_; +} + +double Histogram::StandardDeviation() const { + if (num_ == 0.0) return 0; + double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); + return sqrt(variance); +} + +std::string Histogram::ToString() const { + std::string r; + char buf[200]; + snprintf(buf, sizeof(buf), + "Count: %.0f Average: %.4f StdDev: %.2f\n", + num_, Average(), StandardDeviation()); + r.append(buf); + snprintf(buf, sizeof(buf), + "Min: %.4f Median: %.4f Max: %.4f\n", + (num_ == 0.0 ? 0.0 : min_), Median(), max_); + r.append(buf); + r.append("------------------------------------------------------\n"); + const double mult = 100.0 / num_; + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + if (buckets_[b] <= 0.0) continue; + sum += buckets_[b]; + snprintf(buf, sizeof(buf), + "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", + ((b == 0) ? 0.0 : kBucketLimit[b-1]), // left + kBucketLimit[b], // right + buckets_[b], // count + mult * buckets_[b], // percentage + mult * sum); // cumulative percentage + r.append(buf); + + // Add hash marks based on percentage; 20 marks for 100%. + int marks = static_cast(20*(buckets_[b] / num_) + 0.5); + r.append(marks, '#'); + r.push_back('\n'); + } + return r; +} + +} // namespace leveldb diff --git a/util/histogram.h b/util/histogram.h new file mode 100644 index 000000000..1ef9f3c8a --- /dev/null +++ b/util/histogram.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ +#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ + +#include + +namespace leveldb { + +class Histogram { + public: + Histogram() { } + ~Histogram() { } + + void Clear(); + void Add(double value); + void Merge(const Histogram& other); + + std::string ToString() const; + + private: + double min_; + double max_; + double num_; + double sum_; + double sum_squares_; + + enum { kNumBuckets = 154 }; + static const double kBucketLimit[kNumBuckets]; + double buckets_[kNumBuckets]; + + double Median() const; + double Percentile(double p) const; + double Average() const; + double StandardDeviation() const; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/util/logging.cc b/util/logging.cc new file mode 100644 index 000000000..22cf27851 --- /dev/null +++ b/util/logging.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/logging.h" + +#include +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" + +namespace leveldb { + +void AppendNumberTo(std::string* str, uint64_t num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num); + str->append(buf); +} + +void AppendEscapedStringTo(std::string* str, const Slice& value) { + for (size_t i = 0; i < value.size(); i++) { + char c = value[i]; + if (c >= ' ' && c <= '~') { + str->push_back(c); + } else { + char buf[10]; + snprintf(buf, sizeof(buf), "\\x%02x", + static_cast(c) & 0xff); + str->append(buf); + } + } +} + +std::string NumberToString(uint64_t num) { + std::string r; + AppendNumberTo(&r, num); + return r; +} + +std::string EscapeString(const Slice& value) { + std::string r; + AppendEscapedStringTo(&r, value); + return r; +} + +bool ConsumeChar(Slice* in, char c) { + if (!in->empty() && (*in)[0] == c) { + in->remove_prefix(1); + return true; + } else { + return false; + } +} + +bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { + uint64_t v = 0; + int digits = 0; + while (!in->empty()) { + char c = (*in)[0]; + if (c >= '0' && c <= '9') { + ++digits; + const int delta = (c - '0'); + static const uint64_t kMaxUint64 = ~static_cast(0); + if (v > kMaxUint64/10 || + (v == kMaxUint64/10 && delta > kMaxUint64%10)) { + // Overflow + return false; + } + v = (v * 10) + delta; + in->remove_prefix(1); + } else { + break; + } + } + *val = v; + return (digits > 0); +} + +} // namespace leveldb diff --git a/util/logging.h b/util/logging.h new file mode 100644 index 000000000..b0c5da813 --- /dev/null +++ b/util/logging.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Must not be included from any .h files to avoid polluting the namespace +// with macros. + +#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ +#define STORAGE_LEVELDB_UTIL_LOGGING_H_ + +#include +#include +#include +#include "port/port.h" + +namespace leveldb { + +class Slice; +class WritableFile; + +// Append a human-readable printout of "num" to *str +extern void AppendNumberTo(std::string* str, uint64_t num); + +// Append a human-readable printout of "value" to *str. +// Escapes any non-printable characters found in "value". +extern void AppendEscapedStringTo(std::string* str, const Slice& value); + +// Return a human-readable printout of "num" +extern std::string NumberToString(uint64_t num); + +// Return a human-readable version of "value". +// Escapes any non-printable characters found in "value". +extern std::string EscapeString(const Slice& value); + +// If *in starts with "c", advances *in past the first character and +// returns true. Otherwise, returns false. +extern bool ConsumeChar(Slice* in, char c); + +// Parse a human-readable number from "*in" into *value. On success, +// advances "*in" past the consumed number and sets "*val" to the +// numeric value. Otherwise, returns false and leaves *in in an +// unspecified state. +extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/util/mutexlock.h b/util/mutexlock.h new file mode 100644 index 000000000..1ff5a9efa --- /dev/null +++ b/util/mutexlock.h @@ -0,0 +1,41 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ +#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ + +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +// Helper class that locks a mutex on construction and unlocks the mutex when +// the destructor of the MutexLock object is invoked. +// +// Typical usage: +// +// void MyClass::MyMethod() { +// MutexLock l(&mu_); // mu_ is an instance variable +// ... some complex code, possibly with multiple return paths ... +// } + +class SCOPED_LOCKABLE MutexLock { + public: + explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) + : mu_(mu) { + this->mu_->Lock(); + } + ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } + + private: + port::Mutex *const mu_; + // No copying allowed + MutexLock(const MutexLock&); + void operator=(const MutexLock&); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/util/options.cc b/util/options.cc new file mode 100644 index 000000000..76af5b930 --- /dev/null +++ b/util/options.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/options.h" + +#include "leveldb/comparator.h" +#include "leveldb/env.h" + +namespace leveldb { + +Options::Options() + : comparator(BytewiseComparator()), + create_if_missing(false), + error_if_exists(false), + paranoid_checks(false), + env(Env::Default()), + info_log(NULL), + write_buffer_size(4<<20), + max_open_files(1000), + block_cache(NULL), + block_size(4096), + block_restart_interval(16), + compression(kSnappyCompression), + filter_policy(NULL) { +} + + +} // namespace leveldb diff --git a/util/posix_logger.h b/util/posix_logger.h new file mode 100644 index 000000000..c063c2b7c --- /dev/null +++ b/util/posix_logger.h @@ -0,0 +1,98 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Logger implementation that can be shared by all environments +// where enough Posix functionality is available. + +#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ + +#include +#include +#include +#include +#include "leveldb/env.h" + +namespace leveldb { + +class PosixLogger : public Logger { + private: + FILE* file_; + uint64_t (*gettid_)(); // Return the thread id for the current thread + public: + PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } + virtual ~PosixLogger() { + fclose(file_); + } + virtual void Logv(const char* format, va_list ap) { + const uint64_t thread_id = (*gettid_)(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + char buffer[500]; + for (int iter = 0; iter < 2; iter++) { + char* base; + int bufsize; + if (iter == 0) { + bufsize = sizeof(buffer); + base = buffer; + } else { + bufsize = 30000; + base = new char[bufsize]; + } + char* p = base; + char* limit = base + bufsize; + + struct timeval now_tv; + gettimeofday(&now_tv, NULL); + const time_t seconds = now_tv.tv_sec; + struct tm t; + localtime_r(&seconds, &t); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + t.tm_year + 1900, + t.tm_mon + 1, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + static_cast(now_tv.tv_usec), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + p += vsnprintf(p, limit - p, format, backup_ap); + va_end(backup_ap); + } + + // Truncate to available space if necessary + if (p >= limit) { + if (iter == 0) { + continue; // Try again with larger buffer + } else { + p = limit - 1; + } + } + + // Add newline if necessary + if (p == base || p[-1] != '\n') { + *p++ = '\n'; + } + + assert(p <= limit); + fwrite(base, 1, p - base, file_); + fflush(file_); + if (base != buffer) { + delete[] base; + } + break; + } + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/util/random.h b/util/random.h new file mode 100644 index 000000000..07538242e --- /dev/null +++ b/util/random.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ +#define STORAGE_LEVELDB_UTIL_RANDOM_H_ + +#include + +namespace leveldb { + +// A very simple random number generator. Not especially good at +// generating truly random bits, but good enough for our needs in this +// package. +class Random { + private: + uint32_t seed_; + public: + explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { } + uint32_t Next() { + static const uint32_t M = 2147483647L; // 2^31-1 + static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 + // We are computing + // seed_ = (seed_ * A) % M, where M = 2^31-1 + // + // seed_ must not be zero or M, or else all subsequent computed values + // will be zero or M respectively. For all other values, seed_ will end + // up cycling through every number in [1,M-1] + uint64_t product = seed_ * A; + + // Compute (product % M) using the fact that ((x << 31) % M) == x. + seed_ = static_cast((product >> 31) + (product & M)); + // The first reduction may overflow by 1 bit, so we may need to + // repeat. mod == M is not possible; using > allows the faster + // sign-bit-based test. + if (seed_ > M) { + seed_ -= M; + } + return seed_; + } + // Returns a uniformly distributed value in the range [0..n-1] + // REQUIRES: n > 0 + uint32_t Uniform(int n) { return Next() % n; } + + // Randomly returns true ~"1/n" of the time, and false otherwise. + // REQUIRES: n > 0 + bool OneIn(int n) { return (Next() % n) == 0; } + + // Skewed: pick "base" uniformly from range [0,max_log] and then + // return "base" random bits. The effect is to pick a number in the + // range [0,2^max_log-1] with exponential bias towards smaller numbers. + uint32_t Skewed(int max_log) { + return Uniform(1 << Uniform(max_log + 1)); + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/util/status.cc b/util/status.cc new file mode 100644 index 000000000..a44f35b31 --- /dev/null +++ b/util/status.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "port/port.h" +#include "leveldb/status.h" + +namespace leveldb { + +const char* Status::CopyState(const char* state) { + uint32_t size; + memcpy(&size, state, sizeof(size)); + char* result = new char[size + 5]; + memcpy(result, state, size + 5); + return result; +} + +Status::Status(Code code, const Slice& msg, const Slice& msg2) { + assert(code != kOk); + const uint32_t len1 = msg.size(); + const uint32_t len2 = msg2.size(); + const uint32_t size = len1 + (len2 ? (2 + len2) : 0); + char* result = new char[size + 5]; + memcpy(result, &size, sizeof(size)); + result[4] = static_cast(code); + memcpy(result + 5, msg.data(), len1); + if (len2) { + result[5 + len1] = ':'; + result[6 + len1] = ' '; + memcpy(result + 7 + len1, msg2.data(), len2); + } + state_ = result; +} + +std::string Status::ToString() const { + if (state_ == NULL) { + return "OK"; + } else { + char tmp[30]; + const char* type; + switch (code()) { + case kOk: + type = "OK"; + break; + case kNotFound: + type = "NotFound: "; + break; + case kCorruption: + type = "Corruption: "; + break; + case kNotSupported: + type = "Not implemented: "; + break; + case kInvalidArgument: + type = "Invalid argument: "; + break; + case kIOError: + type = "IO error: "; + break; + default: + snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", + static_cast(code())); + type = tmp; + break; + } + std::string result(type); + uint32_t length; + memcpy(&length, state_, sizeof(length)); + result.append(state_ + 5, length); + return result; + } +} + +} // namespace leveldb diff --git a/util/testharness.cc b/util/testharness.cc new file mode 100644 index 000000000..eb1bdd554 --- /dev/null +++ b/util/testharness.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testharness.h" + +#include +#include +#include +#include + +namespace leveldb { +namespace test { + +namespace { +struct Test { + const char* base; + const char* name; + void (*func)(); +}; +std::vector* tests; +} + +bool RegisterTest(const char* base, const char* name, void (*func)()) { + if (tests == NULL) { + tests = new std::vector; + } + Test t; + t.base = base; + t.name = name; + t.func = func; + tests->push_back(t); + return true; +} + +int RunAllTests() { + const char* matcher = getenv("LEVELDB_TESTS"); + + int num = 0; + if (tests != NULL) { + for (int i = 0; i < tests->size(); i++) { + const Test& t = (*tests)[i]; + if (matcher != NULL) { + std::string name = t.base; + name.push_back('.'); + name.append(t.name); + if (strstr(name.c_str(), matcher) == NULL) { + continue; + } + } + fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); + (*t.func)(); + ++num; + } + } + fprintf(stderr, "==== PASSED %d tests\n", num); + return 0; +} + +std::string TmpDir() { + std::string dir; + Status s = Env::Default()->GetTestDirectory(&dir); + ASSERT_TRUE(s.ok()) << s.ToString(); + return dir; +} + +int RandomSeed() { + const char* env = getenv("TEST_RANDOM_SEED"); + int result = (env != NULL ? atoi(env) : 301); + if (result <= 0) { + result = 301; + } + return result; +} + +} // namespace test +} // namespace leveldb diff --git a/util/testharness.h b/util/testharness.h new file mode 100644 index 000000000..da4fe68bb --- /dev/null +++ b/util/testharness.h @@ -0,0 +1,138 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ +#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ + +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Run some of the tests registered by the TEST() macro. If the +// environment variable "LEVELDB_TESTS" is not set, runs all tests. +// Otherwise, runs only the tests whose name contains the value of +// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: +// TEST(Foo, Hello) { ... } +// TEST(Foo, World) { ... } +// LEVELDB_TESTS=Hello will run the first test +// LEVELDB_TESTS=o will run both tests +// LEVELDB_TESTS=Junk will run no tests +// +// Returns 0 if all tests pass. +// Dies or returns a non-zero value if some test fails. +extern int RunAllTests(); + +// Return the directory to use for temporary storage. +extern std::string TmpDir(); + +// Return a randomization seed for this run. Typically returns the +// same number on repeated invocations of this binary, but automated +// runs may be able to vary the seed. +extern int RandomSeed(); + +// An instance of Tester is allocated to hold temporary state during +// the execution of an assertion. +class Tester { + private: + bool ok_; + const char* fname_; + int line_; + std::stringstream ss_; + + public: + Tester(const char* f, int l) + : ok_(true), fname_(f), line_(l) { + } + + ~Tester() { + if (!ok_) { + fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); + exit(1); + } + } + + Tester& Is(bool b, const char* msg) { + if (!b) { + ss_ << " Assertion failure " << msg; + ok_ = false; + } + return *this; + } + + Tester& IsOk(const Status& s) { + if (!s.ok()) { + ss_ << " " << s.ToString(); + ok_ = false; + } + return *this; + } + +#define BINARY_OP(name,op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (! (x op y)) { \ + ss_ << " failed: " << x << (" " #op " ") << y; \ + ok_ = false; \ + } \ + return *this; \ + } + + BINARY_OP(IsEq, ==) + BINARY_OP(IsNe, !=) + BINARY_OP(IsGe, >=) + BINARY_OP(IsGt, >) + BINARY_OP(IsLe, <=) + BINARY_OP(IsLt, <) +#undef BINARY_OP + + // Attach the specified value to the error message if an error has occurred + template + Tester& operator<<(const V& value) { + if (!ok_) { + ss_ << " " << value; + } + return *this; + } +}; + +#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) +#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) +#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) +#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) +#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) +#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) +#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) +#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) + +#define TCONCAT(a,b) TCONCAT1(a,b) +#define TCONCAT1(a,b) a##b + +#define TEST(base,name) \ +class TCONCAT(_Test_,name) : public base { \ + public: \ + void _Run(); \ + static void _RunIt() { \ + TCONCAT(_Test_,name) t; \ + t._Run(); \ + } \ +}; \ +bool TCONCAT(_Test_ignored_,name) = \ + ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \ +void TCONCAT(_Test_,name)::_Run() + +// Register the specified test. Typically not used directly, but +// invoked via the macro expansion of TEST. +extern bool RegisterTest(const char* base, const char* name, void (*func)()); + + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/util/testutil.cc b/util/testutil.cc new file mode 100644 index 000000000..538d09516 --- /dev/null +++ b/util/testutil.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testutil.h" + +#include "util/random.h" + +namespace leveldb { +namespace test { + +Slice RandomString(Random* rnd, int len, std::string* dst) { + dst->resize(len); + for (int i = 0; i < len; i++) { + (*dst)[i] = static_cast(' ' + rnd->Uniform(95)); // ' ' .. '~' + } + return Slice(*dst); +} + +std::string RandomKey(Random* rnd, int len) { + // Make sure to generate a wide variety of characters so we + // test the boundary conditions for short-key optimizations. + static const char kTestChars[] = { + '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' + }; + std::string result; + for (int i = 0; i < len; i++) { + result += kTestChars[rnd->Uniform(sizeof(kTestChars))]; + } + return result; +} + + +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + int len, std::string* dst) { + int raw = static_cast(len * compressed_fraction); + if (raw < 1) raw = 1; + std::string raw_data; + RandomString(rnd, raw, &raw_data); + + // Duplicate the random data until we have filled "len" bytes + dst->clear(); + while (dst->size() < len) { + dst->append(raw_data); + } + dst->resize(len); + return Slice(*dst); +} + +} // namespace test +} // namespace leveldb diff --git a/util/testutil.h b/util/testutil.h new file mode 100644 index 000000000..824e655bd --- /dev/null +++ b/util/testutil.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ +#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ + +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Store in *dst a random string of length "len" and return a Slice that +// references the generated data. +extern Slice RandomString(Random* rnd, int len, std::string* dst); + +// Return a random key with the specified length that may contain interesting +// characters (e.g. \x00, \xff, etc.). +extern std::string RandomKey(Random* rnd, int len); + +// Store in *dst a string of length "len" that will compress to +// "N*compressed_fraction" bytes and return a Slice that references +// the generated data. +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + int len, std::string* dst); + +// A wrapper that allows injection of errors. +class ErrorEnv : public EnvWrapper { + public: + bool writable_file_error_; + int num_writable_file_errors_; + + ErrorEnv() : EnvWrapper(Env::Default()), + writable_file_error_(false), + num_writable_file_errors_(0) { } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = NULL; + return Status::IOError(fname, "fake error"); + } + return target()->NewWritableFile(fname, result); + } +}; + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ From b9763faf128d351e7bdc9151af062073a9659bec Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sat, 4 May 2013 12:30:14 +0200 Subject: [PATCH 26/69] translations update 2013-05-04 - updates bitcoin_en.ts and bitcoinstrings.cpp - removes bitcoin_se.ts - adds bitcoin_ar.ts - integrates current translations from Transifex --- src/qt/bitcoin.qrc | 2 +- src/qt/bitcoinstrings.cpp | 11 +- .../locale/{bitcoin_se.ts => bitcoin_ar.ts} | 142 ++++++++------- src/qt/locale/bitcoin_bg.ts | 108 ++++++----- src/qt/locale/bitcoin_bs.ts | 108 ++++++----- src/qt/locale/bitcoin_ca.ts | 108 ++++++----- src/qt/locale/bitcoin_ca_ES.ts | 110 +++++++----- src/qt/locale/bitcoin_cs.ts | 110 +++++++----- src/qt/locale/bitcoin_cy.ts | 108 ++++++----- src/qt/locale/bitcoin_da.ts | 110 +++++++----- src/qt/locale/bitcoin_de.ts | 114 +++++++----- src/qt/locale/bitcoin_el_GR.ts | 130 ++++++++------ src/qt/locale/bitcoin_en.ts | 151 ++++++++-------- src/qt/locale/bitcoin_eo.ts | 108 ++++++----- src/qt/locale/bitcoin_es.ts | 112 +++++++----- src/qt/locale/bitcoin_es_CL.ts | 108 ++++++----- src/qt/locale/bitcoin_et.ts | 110 +++++++----- src/qt/locale/bitcoin_eu_ES.ts | 150 +++++++++------- src/qt/locale/bitcoin_fa.ts | 108 ++++++----- src/qt/locale/bitcoin_fa_IR.ts | 108 ++++++----- src/qt/locale/bitcoin_fi.ts | 110 +++++++----- src/qt/locale/bitcoin_fr.ts | 112 +++++++----- src/qt/locale/bitcoin_fr_CA.ts | 108 ++++++----- src/qt/locale/bitcoin_gu_IN.ts | 108 ++++++----- src/qt/locale/bitcoin_he.ts | 110 +++++++----- src/qt/locale/bitcoin_hi_IN.ts | 108 ++++++----- src/qt/locale/bitcoin_hr.ts | 136 ++++++++------ src/qt/locale/bitcoin_hu.ts | 108 ++++++----- src/qt/locale/bitcoin_it.ts | 122 +++++++------ src/qt/locale/bitcoin_ja.ts | 108 ++++++----- src/qt/locale/bitcoin_la.ts | 114 +++++++----- src/qt/locale/bitcoin_lt.ts | 108 ++++++----- src/qt/locale/bitcoin_lv_LV.ts | 108 ++++++----- src/qt/locale/bitcoin_nb.ts | 108 ++++++----- src/qt/locale/bitcoin_nl.ts | 110 +++++++----- src/qt/locale/bitcoin_pl.ts | 110 +++++++----- src/qt/locale/bitcoin_pt_BR.ts | 110 +++++++----- src/qt/locale/bitcoin_pt_PT.ts | 110 +++++++----- src/qt/locale/bitcoin_ro_RO.ts | 108 ++++++----- src/qt/locale/bitcoin_ru.ts | 110 +++++++----- src/qt/locale/bitcoin_sk.ts | 108 ++++++----- src/qt/locale/bitcoin_sr.ts | 108 ++++++----- src/qt/locale/bitcoin_sv.ts | 110 +++++++----- src/qt/locale/bitcoin_th_TH.ts | 168 ++++++++++-------- src/qt/locale/bitcoin_tr.ts | 110 +++++++----- src/qt/locale/bitcoin_uk.ts | 110 +++++++----- src/qt/locale/bitcoin_zh_CN.ts | 110 +++++++----- src/qt/locale/bitcoin_zh_TW.ts | 136 ++++++++------ 48 files changed, 3052 insertions(+), 2250 deletions(-) rename src/qt/locale/{bitcoin_se.ts => bitcoin_ar.ts} (96%) diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index a8379597b..0ec90a294 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -50,6 +50,7 @@ res/movies/update_spinner.mng + locale/bitcoin_ar.qm locale/bitcoin_bg.qm locale/bitcoin_bs.ts locale/bitcoin_ca.ts @@ -87,7 +88,6 @@ locale/bitcoin_pt_PT.qm locale/bitcoin_ro_RO.qm locale/bitcoin_ru.qm - locale/bitcoin_se.qm locale/bitcoin_sk.qm locale/bitcoin_sr.qm locale/bitcoin_sv.qm diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 4f3bb1064..5481b5ce0 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -33,9 +33,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot obtain a lock on data directory %s. Bitcoin is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Error initializing database environment %s! To recover, BACKUP THAT " -"DIRECTORY, then remove everything from it except for wallet.dat."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: The transaction was rejected! This might happen if some of the coins " "in your wallet were already spent, such as if you used a copy of wallet.dat " "and coins were spent in the copy but not marked as spent here."), @@ -60,7 +57,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Set maximum size of high-priority/low-fee transactions in bytes (default: " "27000)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Set the number of script verification threads (1-16, 0=auto, default: 0)"), +"Set the number of script verification threads (up to 16, 0 = auto, <0 = " +"leave that many cores free, default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "This is a pre-release test build - use at your own risk - do not use for " "mining or merchant applications"), @@ -96,7 +94,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrup QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"), QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), -QT_TRANSLATE_NOOP("bitcoin-core", "Cannot initialize keypool"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"), @@ -106,7 +103,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"), QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), -QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environment %s!"), @@ -133,7 +129,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write transaction index"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data"), QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"), QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1 unless -connect)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"), +QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"), QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 288, 0 = all)"), QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-4, default: 3)"), @@ -153,6 +149,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Maintain a full transaction index (default: 0 QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most connections to peers (default: 125)"), QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, *1000 bytes (default: 5000)"), QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, *1000 bytes (default: 1000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."), QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: 1)"), QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network (IPv4, IPv6 or Tor)"), QT_TRANSLATE_NOOP("bitcoin-core", "Options:"), diff --git a/src/qt/locale/bitcoin_se.ts b/src/qt/locale/bitcoin_ar.ts similarity index 96% rename from src/qt/locale/bitcoin_se.ts rename to src/qt/locale/bitcoin_ar.ts index ef468f74b..08045edde 100644 --- a/src/qt/locale/bitcoin_se.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -1,16 +1,16 @@ - + UTF-8 AboutDialog About Bitcoin - + عن Bitcoin <b>Bitcoin</b> version - + نسخة <b>Bitcoin</b> @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -38,22 +38,22 @@ This product includes software developed by the OpenSSL Project for use in the O Address Book - + كتاب العنوانين Double-click to edit address or label - + أنقر على الماوس مرتين لتعديل عنوان Create a new address - + قم بعمل عنوان جديد Copy the currently selected address to the system clipboard - + قم بنسخ القوانين المختارة لحافظة النظام @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -103,7 +113,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Delete - + &أمسح @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File - + &Settings @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Actions toolbar - - - - + [testnet] @@ -542,10 +537,15 @@ This product includes software developed by the OpenSSL Project for use in the O %n active connection(s) to Bitcoin network - + - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -557,20 +557,20 @@ This product includes software developed by the OpenSSL Project for use in the O %n hour(s) - + %n day(s) - + %n week(s) - + - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date - + Catching up... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -1666,7 +1679,7 @@ Address: %4 , broadcast through %n node(s) - + @@ -1719,7 +1732,7 @@ Address: %4 matures in %n more block(s) - + @@ -1802,7 +1815,7 @@ Address: %4 Open for %n more block(s) - + @@ -1848,7 +1861,7 @@ Address: %4 Open for %n more block(s) - + @@ -1873,7 +1886,7 @@ Address: %4 Mined balance will be available when it matures in %n more block(s) - + @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 40c75a679..52c88822d 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -28,13 +28,13 @@ This product includes software developed by the OpenSSL Project for use in the O Използван е софтуер, разработен от OpenSSL Project за употреба в OpenSSL Toolkit (http://www.openssl.org/), криптографски софтуер разработен от Eric Young (eay@cryptsoft.com) и UPnP софтуер разработен от Thomas Bernard. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Нов адрес - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Това са вашите Биткоин адреси за получаване на плащания. За по-лесно проследяване на плащанията и повишена анонимност можете да използвате нов адрес за всяко плащане. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O Изтрий избрания адрес от списъка - + + Export the data in the current tab to a file + Запишете данните от текущия раздел във файл + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Проверете съобщение, за да сте сигурни че е подписано с определен Биткоин адрес @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Подписване на &съобщение... - + Synchronizing with network... Синхронизиране с мрежата... - + &Overview &Баланс @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Смяна на паролата... - + Importing blocks from disk... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Експорт... - - - + Send coins to a Bitcoin address Изпращане към Биткоин адрес @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - Запишете данните от текущия раздел във файл - - - + Backup wallet to another location @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O Променя паролата за портфейла - + &Debug window @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... &Проверка на съобщение... - - + + Bitcoin Биткоин - + Wallet Портфейл - + &Send @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Файл - + &Settings &Настройки @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O Раздели - - Actions toolbar - Функции - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n връзка към Биткоин мрежата%n връзки към Биткоин мрежата - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Синхронизиран - + Catching up... Зарежда блокове... - + Confirm transaction fee Потвърждение за такса @@ -666,7 +666,7 @@ Address: %4 Портфейлът е <b>криптиран</b> и <b>заключен</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -674,7 +674,7 @@ Address: %4 ClientModel - + Network Alert @@ -1055,7 +1055,7 @@ Address: %4 Сборът на все още непотвърдените транзакции, които не са част от текущия баланс - + out of sync несинхронизиран @@ -1641,6 +1641,19 @@ Address: %4 Съобщението е потвърдено. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2118,7 +2131,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + Запишете данните от текущия раздел във файл + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 32b3e63a0..4f6064d5a 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File - + &Settings @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Actions toolbar - - - - + [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date - + Catching up... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 94372bbf0..482005bdb 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File - + &Settings @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Actions toolbar - - - - + [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date - + Catching up... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 6c6658910..864cfeb37 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -23,14 +23,14 @@ This product includes software developed by the OpenSSL Project for use in the O \n Aquest és software experimental.\n\n Distribuït sota llicència de software MIT/11, veure l'arxiu COPYING o http://www.opensource.org/licenses/mit-license.php.\n\nAquest producte inclou software desarrollat pel projecte OpenSSL per a l'ús de OppenSSL Toolkit (http://www.openssl.org/) i de softwqre criptogràfic escrit per l'Eric Young (eay@cryptsoft.com) i software UPnP escrit per en Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Els creadors de Bitcoin + The Bitcoin developers + @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Nova adreça - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Aquestes són les teves adreces Bitcoin per a rebre pagaments. Pot interesar-te proveïr diferents adreces a cadascun dels enviadors així pots identificar qui et va pagant. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O Esborrar l'adreça sel·leccionada - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Verificar un missatge per asegurar-se que ha estat signat amb una adreça Bitcoin específica @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Signar &missatge... - + Synchronizing with network... Sincronitzant amb la xarxa ... - + &Overview &Panorama general @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Canviar contrasenya... - + Importing blocks from disk... Important blocs del disc.. @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O Re-indexant blocs al disc... - - &Export... - &Exporta... - - - + Send coins to a Bitcoin address Enviar monedes a una adreça Bitcoin @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O Modificar les opcions de configuració per bitcoin - - Export the data in the current tab to a file - Exportar dades de la pestanya actual a un fitxer - - - + Backup wallet to another location Realitzar còpia de seguretat del moneder a un altre directori @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Canviar la constrasenya d'encriptació del moneder - + &Debug window &Finestra de debug @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O Obrir la consola de diagnòstic i debugging - + &Verify message... &Verifica el missatge.. - - + + Bitcoin Bitcoin - + Wallet Moneder - + &Send &Enviar @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O Verificar els missatges per assegurar-te que han estat signades amb una adreça Bitcoin específica. - + &File &Arxiu - + &Settings &Configuració @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Barra d'eines de seccions - - Actions toolbar - Barra d'eines d'accions - - - + [testnet] [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n connexió activa a la xarxa Bitcoin%n connexions actives a la xarxa Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Processat el %1 de %2 (estimat) dels blocs del històric de transaccions. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n setmana%n setmanes - + %1 behind %1 radera @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O Les transaccions a partir d'això no seràn visibles. - + Error Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O Informació - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Aquesta transacció supera el límit de tamany. Tot i així pots enviar-la amb una comissió de %1, que es destinen als nodes que processen la seva transacció i ajuda a donar suport a la xarxa. Vols pagar la comissió? - + Up to date Al dia - + Catching up... Posar-se al dia ... - + Confirm transaction fee Confirmar comisió de transacció @@ -661,7 +661,7 @@ Address: %4 El moneder està <b>encriptat</b> i actualment <b>bloquejat</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ha tingut lloc un error fatal. Bitcoin no pot continuar executant-se de manera segura i es tancará. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert Alerta de xarxa @@ -1050,7 +1050,7 @@ Address: %4 Total de transaccions encara sense confirmar, que encara no es content en el balanç actual - + out of sync Fora de sincronia @@ -1636,6 +1636,19 @@ Address: %4 Missatge verificat. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet Realitzar còpia de seguretat del moneder diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index f3ef200ca..2c1e4caf2 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -28,14 +28,14 @@ Tohle je experimentální program. Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v OpenSSL Toolkitu (http://www.openssl.org/) a kryptografický program od Erika Younga (eay@cryptsoft.com) a program UPnP od Thomase Bernarda. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Vývojáři Bitcoinu + The Bitcoin developers + Vývojáři Bitcoinu @@ -66,7 +66,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Nová &adresa - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Tohle jsou tvé Bitcoinové adresy pro příjem plateb. Můžeš dát pokaždé každému plátci novou adresu, abys věděl, kdo ti kdy kolik platil. @@ -96,7 +96,17 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Smaž zvolenou adresu ze seznamu - + + Export the data in the current tab to a file + Exportuj data z tohoto panelu do souboru + + + + &Export + &Export + + + Verify a message to ensure it was signed with a specified Bitcoin address Ověř zprávu, aby ses ujistil, že byla podepsána danou Bitcoinovou adresou @@ -313,17 +323,17 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open BitcoinGUI - + Sign &message... Po&depiš zprávu... - + Synchronizing with network... Synchronizuji se se sítí... - + &Overview &Přehled @@ -398,7 +408,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Změň &heslo... - + Importing blocks from disk... Importuji bloky z disku... @@ -408,12 +418,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Vytvářím nový index bloků na disku... - - &Export... - &Export... - - - + Send coins to a Bitcoin address Pošli mince na Bitcoinovou adresu @@ -423,12 +428,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Uprav nastavení Bitcoinu - - Export the data in the current tab to a file - Exportuj data z tohoto panelu do souboru - - - + Backup wallet to another location Zazálohuj peněženku na jiné místo @@ -438,7 +438,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Změň heslo k šifrování peněženky - + &Debug window &Ladicí okno @@ -448,23 +448,23 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Otevři ladicí a diagnostickou konzoli - + &Verify message... &Ověř zprávu... - - + + Bitcoin Bitcoin - + Wallet Peněženka - + &Send &Pošli @@ -509,12 +509,12 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Ověř zprávy, aby ses ujistil, že byly podepsány danými Bitcoinovými adresami - + &File &Soubor - + &Settings &Nastavení @@ -529,12 +529,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Panel s listy - - Actions toolbar - Panel akcí - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open %n aktivní spojení do Bitcoinové sítě%n aktivní spojení do Bitcoinové sítě%n aktivních spojení do Bitcoinové sítě - + + No block source available... + Není dostupný žádný zdroj bloků... + + + Processed %1 of %2 (estimated) blocks of transaction history. Zpracováno %1 z přibližně %2 bloků transakční historie. @@ -575,7 +575,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open týden%n týdny%n týdnů - + %1 behind Stahuji ještě bloky transakcí za poslední %1 @@ -590,7 +590,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Následné transakce ještě nebudou vidět. - + Error Chyba @@ -605,22 +605,22 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Informace - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Tahle transakce přesahuje velikostní limit. I tak ji ale můžeš poslat, pokud za ni zaplatíš poplatek %1, který půjde uzlům, které tvou transakci zpracují, a navíc tak podpoříš síť. Chceš zaplatit poplatek? - + Up to date Aktuální - + Catching up... Stahuji... - + Confirm transaction fee Potvrď transakční poplatek @@ -670,7 +670,7 @@ Adresa: %4 Peněženka je <b>zašifrovaná</b> a momentálně <b>zamčená</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Stala se fatální chyba. Bitcoin nemůže bezpečně pokračovat v činnosti, a proto skončí. @@ -678,7 +678,7 @@ Adresa: %4 ClientModel - + Network Alert Upozornění sítě @@ -1059,7 +1059,7 @@ Adresa: %4 Celkem z transakcí, které ještě nejsou potvrzené a které se ještě nezapočítávají do celkového stavu účtu - + out of sync nesynchronizováno @@ -1645,6 +1645,19 @@ Adresa: %4 Zpráva ověřena. + + SplashScreen + + + The Bitcoin developers + Vývojáři Bitcoinu + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Adresa: %4 WalletView - + + Export the data in the current tab to a file + Exportuj data z tohoto panelu do souboru + + + Backup Wallet Záloha peněženky diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index 453def717..e51229085 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... Cysoni â'r rhwydwaith... - + &Overview &Trosolwg @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Allforio... - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Newid y cyfrinymadrodd a ddefnyddiwyd ar gyfer amgryptio'r waled - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Ffeil - + &Settings &Gosodiadau @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bar offer tabiau - - Actions toolbar - Bar offer camau gweithredu - - - + [testnet] [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Cyfamserol - + Catching up... Dal i fyny - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 Mae'r waled <b>wedi'i amgryptio</b> ac <b>ar glo</b> ar hyn o bryd - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 Cyfanswm o drafodion sydd heb eu cadarnhau a heb eu cyfri tuag at y gweddill presennol - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 700680ec6..e05c1f4c9 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -28,14 +28,14 @@ Det er gjort tilgængeligt under MIT/X11-softwarelicensen. Se den tilhørende fi Produktet indeholder software som er udviklet af OpenSSL Project til brug i OpenSSL Toolkit (http://www.openssl.org/), kryptografisk software skrevet af Eric Young (eay@cryptsoft.com) og UPnP-software skrevet af Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Bitcoin-udviklerne + The Bitcoin developers + Bitcoin-udviklerne @@ -66,7 +66,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Ny adresse - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Dette er dine Bitcoin-adresser til at modtage betalinger med. Du kan give en forskellig adresse til hver afsender, så du kan holde styr på, hvem der betaler dig. @@ -96,7 +96,17 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Slet den markerede adresse fra listen - + + Export the data in the current tab to a file + Eksportér den aktuelle visning til en fil + + + + &Export + Eksporter + + + Verify a message to ensure it was signed with a specified Bitcoin address Efterprøv en besked for at sikre, at den er underskrevet med den angivne Bitcoin-adresse @@ -313,17 +323,17 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open BitcoinGUI - + Sign &message... Underskriv besked... - + Synchronizing with network... Synkroniserer med netværk... - + &Overview Oversigt @@ -398,7 +408,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Skift adgangskode... - + Importing blocks from disk... Importerer blokke fra disken... @@ -408,12 +418,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Genindekserer blokke på disken... - - &Export... - Eksporter... - - - + Send coins to a Bitcoin address Send bitcoins til en Bitcoin-adresse @@ -423,12 +428,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Rediger konfigurationsindstillinger af Bitcoin - - Export the data in the current tab to a file - Eksporter den aktuelle visning til en fil - - - + Backup wallet to another location Lav sikkerhedskopi af tegnebogen til et andet sted @@ -438,7 +438,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Skift adgangskode anvendt til tegnebogskryptering - + &Debug window Fejlsøgningsvindue @@ -448,23 +448,23 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Åbn fejlsøgnings- og diagnosticeringskonsollen - + &Verify message... Efterprøv besked... - - + + Bitcoin Bitcoin - + Wallet Tegnebog - + &Send Send @@ -509,12 +509,12 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Efterprøv beskeder for at sikre, at de er underskrevet med de(n) angivne Bitcoin-adresse(r) - + &File Fil - + &Settings Indstillinger @@ -529,12 +529,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Faneværktøjslinje - - Actions toolbar - Handlingsværktøjslinje - - - + [testnet] [testnetværk] @@ -550,7 +545,12 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open %n aktiv(e) forbindelse(r) til Bitcoin-netværket%n aktiv(e) forbindelse(r) til Bitcoin-netværket - + + No block source available... + Ingen blokkilde tilgængelig... + + + Processed %1 of %2 (estimated) blocks of transaction history. %1 ud af %2 (estimeret) blokke af transaktionshistorikken er blevet behandlet. @@ -575,7 +575,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open %n uge(r)%n uge(r) - + %1 behind %1 bagefter @@ -590,7 +590,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Transaktioner herefter vil endnu ikke være synlige. - + Error Fejl @@ -605,22 +605,22 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Information - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Transaktionen overskrider størrelsesgrænsen. Du kan stadig sende den for et gebyr på %1, hvilket går til de knuder, der behandler din transaktion og hjælper med at understøtte netværket. Vil du betale gebyret? - + Up to date Opdateret - + Catching up... Indhenter... - + Confirm transaction fee Bekræft transaktionsgebyr @@ -670,7 +670,7 @@ Adresse: %4 Tegnebog er <b>krypteret</b> og i øjeblikket <b>låst</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Der opstod en fatal fejl. Bitcoin kan ikke længere fortsætte sikkert og vil afslutte. @@ -678,7 +678,7 @@ Adresse: %4 ClientModel - + Network Alert Netværksadvarsel @@ -1059,7 +1059,7 @@ Adresse: %4 Summen af transaktioner, der endnu ikke er bekræftet og endnu ikke er inkluderet i den nuværende saldo - + out of sync ikke synkroniseret @@ -1645,6 +1645,19 @@ Adresse: %4 Besked efterprøvet. + + SplashScreen + + + The Bitcoin developers + Bitcoin-udviklerne + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Adresse: %4 WalletView - + + Export the data in the current tab to a file + Eksportér den aktuelle visning til en fil + + + Backup Wallet Sikkerhedskopier tegnebog diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 7076d8e2a..ce3a7f396 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -28,14 +28,14 @@ Veröffentlicht unter der MIT/X11-Softwarelizenz, siehe beiligende Datei COPYING Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im OpenSSL-Toolkit (http://www.openssl.org/) entwickelt wurde, sowie kryptographische Software geschrieben von Eric Young (eay@cryptsoft.com) und UPnP-Software geschrieben von Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Die Bitcoinentwickler + The Bitcoin developers + Die Bitcoinentwickler @@ -66,7 +66,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open &Neue Adresse - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Dies sind Ihre Bitcoin-Adressen zum Empfangen von Zahlungen. Es steht Ihnen frei, jedem Absender eine Andere mitzuteilen, um einen besseren Überblick über eingehende Zahlungen zu erhalten. @@ -96,7 +96,17 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Die ausgewählte Adresse aus der Liste entfernen. - + + Export the data in the current tab to a file + Daten der aktuellen Ansicht in eine Datei exportieren + + + + &Export + E&xportieren + + + Verify a message to ensure it was signed with a specified Bitcoin address Eine Nachricht verifizieren, um sicherzustellen, dass diese mit einer angegebenen Bitcoin-Adresse signiert wurde @@ -313,17 +323,17 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open BitcoinGUI - + Sign &message... Nachricht s&ignieren... - + Synchronizing with network... Synchronisiere mit Netzwerk... - + &Overview &Übersicht @@ -398,7 +408,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Passphrase &ändern... - + Importing blocks from disk... Importiere Blöcke von Laufwerk... @@ -408,12 +418,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Reindiziere Blöcke auf Laufwerk... - - &Export... - &Exportieren... - - - + Send coins to a Bitcoin address Bitcoins an eine Bitcoin-Adresse überweisen @@ -423,12 +428,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Die Konfiguration des Clients bearbeiten - - Export the data in the current tab to a file - Daten der aktuellen Ansicht in eine Datei exportieren - - - + Backup wallet to another location Eine Sicherungskopie der Brieftasche erstellen und abspeichern @@ -438,7 +438,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Ändert die Passphrase, die für die Verschlüsselung der Brieftasche benutzt wird - + &Debug window &Debugfenster @@ -448,23 +448,23 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Debugging- und Diagnosekonsole öffnen - + &Verify message... Nachricht &verifizieren... - - + + Bitcoin Bitcoin - + Wallet Brieftasche - + &Send Überweisen @@ -509,12 +509,12 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Nachrichten verifizieren, um sicherzustellen, dass diese mit den angegebenen Bitcoin-Adressen signiert wurden - + &File &Datei - + &Settings &Einstellungen @@ -529,12 +529,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Registerkartenleiste - - Actions toolbar - Aktionssymbolleiste - - - + [testnet] [Testnetz] @@ -550,7 +545,12 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open %n aktive Verbindung zum Bitcoin-Netzwerk%n aktive Verbindungen zum Bitcoin-Netzwerk - + + No block source available... + Keine Blockquelle verfügbar... + + + Processed %1 of %2 (estimated) blocks of transaction history. %1 von (geschätzten) %2 Blöcken des Transaktionsverlaufs verarbeitet. @@ -575,7 +575,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open %n Woche%n Wochen - + %1 behind %1 im Rückstand @@ -590,7 +590,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Transaktionen hiernach werden noch nicht angezeigt. - + Error Fehler @@ -605,22 +605,22 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Hinweis - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Die Transaktion übersteigt das Größenlimit. Sie können sie trotzdem senden, wenn Sie eine zusätzliche Transaktionsgebühr in Höhe von %1 zahlen. Diese wird an die Knoten verteilt, die Ihre Transaktion bearbeiten und unterstützt damit das Bitcoin-Netzwerk. Möchten Sie die Gebühr bezahlen? - + Up to date Auf aktuellem Stand - + Catching up... Hole auf... - + Confirm transaction fee Transaktionsgebühr bestätigen @@ -669,7 +669,7 @@ Adresse: %4 Brieftasche ist <b>verschlüsselt</b> und aktuell <b>gesperrt</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ein schwerer Fehler ist aufgetreten. Bitcoin kann nicht stabil weiter ausgeführt werden und wird beendet. @@ -677,7 +677,7 @@ Adresse: %4 ClientModel - + Network Alert Netzwerkalarm @@ -1058,7 +1058,7 @@ Adresse: %4 Betrag aus unbestätigten Transaktionen, der noch nicht im aktuellen Kontostand enthalten ist - + out of sync nicht synchron @@ -1135,7 +1135,7 @@ Adresse: %4 Client name - Client Name + Clientname @@ -1154,7 +1154,7 @@ Adresse: %4 Client version - Client Version + Clientversion @@ -1644,6 +1644,19 @@ Adresse: %4 Nachricht verifiziert. + + SplashScreen + + + The Bitcoin developers + Die Bitcoinentwickler + + + + [testnet] + [Testnetz] + + TransactionDesc @@ -2121,7 +2134,12 @@ Adresse: %4 WalletView - + + Export the data in the current tab to a file + Daten der aktuellen Ansicht in eine Datei exportieren + + + Backup Wallet Brieftasche sichern diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 640d9ee7c..3587f3467 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Νέα διεύθυνση - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Αυτές είναι οι Bitcoin διευθύνσεις σας για να λαμβάνετε πληρωμές. Δίνοντας μία ξεχωριστή διεύθυνση σε κάθε αποστολέα, θα μπορείτε να ελέγχετε ποιος σας πληρώνει. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + Εξαγωγή δεδομένων καρτέλας σε αρχείο + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Υπογραφή &Μηνύματος... - + Synchronizing with network... Συγχρονισμός με το δίκτυο... - + &Overview &Επισκόπηση @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Άλλαξε κωδικο πρόσβασης - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Εξαγωγή - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - Εξαγωγή δεδομένων καρτέλας σε αρχείο - - - + Backup wallet to another location Δημιουργία αντιγράφου ασφαλείας πορτοφολιού σε άλλη τοποθεσία @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Αλλαγή του κωδικού κρυπτογράφησης του πορτοφολιού - + &Debug window &Παράθυρο αποσφαλμάτωσης @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O Άνοιγμα κονσόλας αποσφαλμάτωσης και διαγνωστικών - + &Verify message... - + &Επιβεβαίωση μηνύματος - - + + Bitcoin Bitcoin - + Wallet Πορτοφόλι - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Αρχείο - + &Settings &Ρυθμίσεις @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Εργαλειοθήκη καρτελών - - Actions toolbar - Εργαλειοθήκη ενεργειών - - - + [testnet] [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n ενεργή σύνδεση στο δίκτυο Bitcoin%n ενεργές συνδέσεις στο δίκτυο Βitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error Σφάλμα @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Ενημερωμένο - + Catching up... Ενημέρωση... - + Confirm transaction fee Επιβεβαίωση αμοιβής συναλλαγής @@ -665,7 +665,7 @@ Address: %4 Το πορτοφόλι είναι <b>κρυπτογραφημένο</b> και <b>κλειδωμένο</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -673,9 +673,9 @@ Address: %4 ClientModel - + Network Alert - + Ειδοποίηση Δικτύου @@ -733,7 +733,7 @@ Address: %4 The entered address "%1" is not a valid Bitcoin address. - + Η διεύθυνση "%1" δεν είναι έγκυρη Bitcoin διεύθυνση. @@ -1031,7 +1031,7 @@ Address: %4 Immature: - + Ανώριμος @@ -1054,7 +1054,7 @@ Address: %4 Το άθροισμα των συναλλαγών που δεν έχουν ακόμα επιβεβαιωθεί και δεν προσμετρώνται στο τρέχον υπόλοιπό σας - + out of sync εκτός συγχρονισμού @@ -1073,7 +1073,7 @@ Address: %4 QR Code Dialog - + Κώδικας QR @@ -1145,7 +1145,7 @@ Address: %4 N/A - + Μη διαθέσιμο @@ -1165,7 +1165,7 @@ Address: %4 Startup time - + Χρόνος εκκίνησης @@ -1180,12 +1180,12 @@ Address: %4 On testnet - + Στο testnet Block chain - + αλυσίδα εμποδισμού @@ -1365,12 +1365,12 @@ Address: %4 The total exceeds your balance when the %1 transaction fee is included. - + Το σύνολο υπερβαίνει το υπόλοιπό σας όταν συμπεριληφθεί και η αμοιβή %1 Duplicate address found, can only send to each address once per send operation. - + Βρέθηκε η ίδια διεύθυνση δύο φορές. Επιτρέπεται μία μόνο εγγραφή για κάθε διεύθυνση, σε κάθε διαδικασία αποστολής. @@ -1640,6 +1640,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2117,7 +2130,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + Εξαγωγή δεδομένων καρτέλας σε αρχείο + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 557d0d027..151e19bbe 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -325,17 +325,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Sign &message... - + Synchronizing with network... Synchronizing with network... - + &Overview &Overview @@ -410,7 +410,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Change Passphrase... - + Importing blocks from disk... Importing blocks from disk... @@ -420,7 +420,7 @@ This product includes software developed by the OpenSSL Project for use in the O Reindexing blocks on disk... - + Send coins to a Bitcoin address Send coins to a Bitcoin address @@ -455,18 +455,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Verify message... - - + + Bitcoin Bitcoin - + Wallet Wallet - + &Send &Send @@ -542,7 +542,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin client - + %n active connection(s) to Bitcoin network %n active connection to Bitcoin network @@ -684,7 +684,7 @@ Address: %4 Wallet is <b>encrypted</b> and currently <b>locked</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -823,8 +823,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2164,12 +2164,17 @@ Address: %4 WalletView - + + &Export + &Export + + + Export the data in the current tab to a file Export the data in the current tab to a file - + Backup Wallet Backup Wallet @@ -2202,12 +2207,12 @@ Address: %4 bitcoin-core - + Bitcoin version Bitcoin version - + Usage: Usage: @@ -2217,7 +2222,7 @@ Address: %4 Send command to -server or bitcoind - + List commands List commands @@ -2227,7 +2232,7 @@ Address: %4 Get help for a command - + Options: Options: @@ -2242,17 +2247,7 @@ Address: %4 Specify pid file (default: bitcoind.pid) - - Generate coins - Generate coins - - - - Don't generate coins - Don't generate coins - - - + Specify data directory Specify data directory @@ -2262,7 +2257,7 @@ Address: %4 Set database cache size in megabytes (default: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2272,7 +2267,7 @@ Address: %4 Maintain at most <n> connections to peers (default: 125) - + Connect to a node to retrieve peer addresses, and disconnect Connect to a node to retrieve peer addresses, and disconnect @@ -2292,22 +2287,22 @@ Address: %4 Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands Run in the background as a daemon and accept commands @@ -2317,12 +2312,12 @@ Address: %4 Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2361,11 +2356,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2392,12 +2382,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2437,7 +2422,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Block creation options: - + Connect only to the specified node(s) Connect only to the specified node(s) @@ -2457,7 +2442,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Do you want to rebuild the block database now? - + Error initializing block database Error initializing block database @@ -2557,7 +2542,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Find peers using DNS lookup (default: 1 unless -connect) - + + Generate coins (default: 0) + Generate coins (default: 0) + + + How many blocks to check at startup (default: 288, 0 = all) How many blocks to check at startup (default: 288, 0 = all) @@ -2567,7 +2557,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. How thorough the block verification is (0-4, default: 3) - + + Not enough file descriptors available. + Not enough file descriptors available. + + + Rebuild block chain index from current blk000??.dat files Rebuild block chain index from current blk000??.dat files @@ -2587,12 +2582,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verifying wallet... - + Imports blocks from external blk000??.dat file Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + Information Information @@ -2617,7 +2617,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Only accept block chain matching built-in checkpoints (default: 1) @@ -2732,12 +2732,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) Send commands to node running on <ip> (default: 127.0.0.1) @@ -2777,12 +2777,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Server private key (default: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message This help message @@ -2797,12 +2797,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Connect through socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Loading addresses... @@ -2817,12 +2817,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error loading wallet.dat: Wallet requires newer version of Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat Error loading wallet.dat @@ -2832,7 +2832,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' Unknown network specified in -onlynet: '%s' @@ -2852,7 +2852,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot resolve -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Invalid amount for -paytxfee=<amount>: '%s' @@ -2872,7 +2872,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Loading block index... - + Add a node to connect to and attempt to keep the connection open Add a node to connect to and attempt to keep the connection open @@ -2882,7 +2882,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Unable to bind to %s on this computer. Bitcoin is probably already running. - + Fee per KB to add to transactions you send Fee per KB to add to transactions you send @@ -2892,15 +2892,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Loading wallet... - + Cannot downgrade wallet Cannot downgrade wallet - - - Cannot initialize keypool - Cannot initialize keypool - Cannot write default address @@ -2912,22 +2907,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescanning... - + Done loading Done loading - + To use the %s option To use the %s option - + Error Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index 2903e70ba..298c16323 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Nova Adreso - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Subskribu &mesaĝon... - + Synchronizing with network... Sinkronigante kun reto... - + &Overview &Superrigardo @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Anstataŭigu pasfrazon... - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Eksportu... - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... &Kontrolu mesaĝon... - - + + Bitcoin - + Wallet Monujo - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Dosiero - + &Settings &Agordoj @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Actions toolbar - - - - + [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n semajno%n semajnoj - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error Eraro @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Ĝisdata - + Catching up... Ĝisdatigante... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 Monujo estas <b>ĉifrita</b> kaj nun <b>ŝlosita</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert Reta Averto @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index adba3420b..809d8c133 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -31,14 +31,14 @@ el OpenSSL Toolkit (http://www.openssl.org/) y software criptográfico escrito p Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Los desarrolladores de Bitcoin + The Bitcoin developers + Los programadores Bitcoin @@ -69,7 +69,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.&Añadir dirección - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Estas son tus direcciones Bitcoin para recibir pagos. Puedes utilizar una diferente por cada persona emisora para saber quién te está pagando. @@ -99,7 +99,17 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Borrar de la lista la dirección seleccionada - + + Export the data in the current tab to a file + Exportar a un archivo los datos de esta pestaña + + + + &Export + &Exportar + + + Verify a message to ensure it was signed with a specified Bitcoin address Verificar un mensaje para comprobar que fue firmado con la dirección Bitcoin indicada @@ -182,7 +192,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. Enter passphrase - Introducir contraseña + Introducir contraseña @@ -316,17 +326,17 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. BitcoinGUI - + Sign &message... Firmar &mensaje... - + Synchronizing with network... Sincronizando con la red… - + &Overview &Vista general @@ -401,7 +411,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.&Cambiar la contraseña… - + Importing blocks from disk... Importando bloques de disco... @@ -411,12 +421,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Reindexando bloques en disco... - - &Export... - &Exportar… - - - + Send coins to a Bitcoin address Enviar monedas a una dirección Bitcoin @@ -426,12 +431,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Modificar las opciones de configuración de Bitcoin - - Export the data in the current tab to a file - Exportar a un archivo los datos de esta pestaña - - - + Backup wallet to another location Copia de seguridad del monedero en otra ubicación @@ -441,7 +441,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Cambiar la contraseña utilizada para el cifrado del monedero - + &Debug window Ventana de &depuración @@ -451,23 +451,23 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Abrir la consola de depuración y diagnóstico - + &Verify message... &Verificar mensaje... - - + + Bitcoin Bitcoin - + Wallet Monedero - + &Send &Enviar @@ -512,12 +512,12 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Verificar mensajes comprobando que están firmados con direcciones Bitcoin concretas - + &File &Archivo - + &Settings &Configuración @@ -532,12 +532,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Barra de pestañas - - Actions toolbar - Barra de acciones - - - + [testnet] [testnet] @@ -553,7 +548,12 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.%n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin - + + No block source available... + Ninguna origen de bloque disponible ... + + + Processed %1 of %2 (estimated) blocks of transaction history. Se han procesado %1 de %2 (estimación) bloques de historia de transacción. @@ -578,7 +578,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.%n semana%n semanas - + %1 behind %1 detrás @@ -593,7 +593,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Las transacciones que vengan después de esta todavía no serán visibles. - + Error Error @@ -608,22 +608,22 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Información - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Esta transacción supera el límite de tamaño. Puede enviarla con una comisión de %1, destinada a los nodos que procesen su transacción para contribuir al mantenimiento de la red. ¿Desea pagar esta comisión? - + Up to date Actualizado - + Catching up... Recuperando... - + Confirm transaction fee Confirme la tarifa de la transacción @@ -673,7 +673,7 @@ Dirección: %4 El monedero está <b>cifrado</b> y actualmente <b>bloqueado</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ha ocurrido un error crítico. Bitcoin ya no puede continuar con seguridad y se cerrará. @@ -681,7 +681,7 @@ Dirección: %4 ClientModel - + Network Alert Alerta de red @@ -1062,7 +1062,7 @@ Dirección: %4 Total de las transacciones que faltan por confirmar y que no contribuyen al saldo actual - + out of sync desincronizado @@ -1648,6 +1648,19 @@ Dirección: %4 Mensaje verificado. + + SplashScreen + + + The Bitcoin developers + Los programadores Bitcoin + + + + [testnet] + [testnet] + + TransactionDesc @@ -2125,7 +2138,12 @@ Dirección: %4 WalletView - + + Export the data in the current tab to a file + Exportar a un archivo los datos de esta pestaña + + + Backup Wallet Respaldo de monedero diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index 66ab01dd9..0c2d624b2 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -31,13 +31,13 @@ el OpenSSL Toolkit (http://www.openssl.org/), software criptográfico escrito po Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -69,7 +69,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.&Nueva dirección - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Estas son tus direcciones Bitcoin para recibir pagos. Puedes utilizar una diferente por cada persona emisora para saber quien te está pagando. @@ -99,7 +99,17 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + + Export the data in the current tab to a file + Exportar los datos de la pestaña actual a un archivo + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -316,17 +326,17 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. BitcoinGUI - + Sign &message... Firmar &Mensaje... - + Synchronizing with network... Sincronizando con la red... - + &Overview &Vista general @@ -401,7 +411,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.&Cambiar la contraseña... - + Importing blocks from disk... @@ -411,12 +421,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - - &Export... - &Exportar... - - - + Send coins to a Bitcoin address Enviar monedas a una dirección bitcoin @@ -426,12 +431,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.Modifica las opciones de configuración de bitcoin - - Export the data in the current tab to a file - Exportar los datos de la pestaña actual a un archivo - - - + Backup wallet to another location Respaldar billetera en otra ubicación @@ -441,7 +441,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.Cambiar la contraseña utilizada para la codificación de la billetera - + &Debug window @@ -451,23 +451,23 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + &Verify message... - - + + Bitcoin Bitcoin - + Wallet Cartera - + &Send @@ -512,12 +512,12 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + &File &Archivo - + &Settings &Configuración @@ -532,12 +532,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.Barra de pestañas - - Actions toolbar - Barra de acciónes - - - + [testnet] [red-de-pruebas] @@ -553,7 +548,12 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.%n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -578,7 +578,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + %1 behind @@ -593,7 +593,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + Error @@ -608,22 +608,22 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Actualizado - + Catching up... Recuperando... - + Confirm transaction fee @@ -672,7 +672,7 @@ Dirección: %4 La billetera esta <b>codificada</b> y actualmente <b>bloqueda</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -680,7 +680,7 @@ Dirección: %4 ClientModel - + Network Alert @@ -1062,7 +1062,7 @@ Dirección: %4 Total de transacciones que no han sido confirmadas aun, y que no cuentan para el saldo actual. - + out of sync @@ -1648,6 +1648,19 @@ Dirección: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [red-de-pruebas] + + TransactionDesc @@ -2125,7 +2138,12 @@ Dirección: %4 WalletView - + + Export the data in the current tab to a file + Exportar los datos de la pestaña actual a un archivo + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index 6512fca3e..71d08f46f 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -28,14 +28,14 @@ Levitatud MIT/X11 tarkvara litsentsi all, vaata kaasasolevat faili COPYING või Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenSSL Toolkitis (http://www.openssl.org/) ja Eric Young'i poolt loodud krüptograafilist tarkvara (eay@cryptsoft.com) ning Thomas Bernard'i loodud UPnP tarkvara. - + Copyright Autoriõigus - 2009-%1 The Bitcoin developers - 2009-%1 Bitcoini arendajad + The Bitcoin developers + @@ -66,7 +66,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS &Uus aadress - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Maksete saamiseks kasutatavad Bitcoini aadressid. Maksjate paremaks jälgimiseks võib igaühele anda erineva. @@ -96,7 +96,17 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Kustuta märgistatud aadress loetelust - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Kinnita sõnum tõestamaks selle allkirjastatust määratud Bitcoini aadressiga. @@ -313,17 +323,17 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS BitcoinGUI - + Sign &message... Signeeri &sõnum - + Synchronizing with network... Võrgusünkimine... - + &Overview &Ülevaade @@ -398,7 +408,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS &Salafraasi muutmine - + Importing blocks from disk... Impordi blokid kettalt... @@ -408,12 +418,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Kettal olevate blokkide re-indekseerimine... - - &Export... - &Ekspordi... - - - + Send coins to a Bitcoin address Saada münte Bitcoini aadressile @@ -423,12 +428,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Muuda Bitcoini seadeid - - Export the data in the current tab to a file - Ekspordi kuvatava vahelehe sisu faili - - - + Backup wallet to another location Varunda rahakott teise asukohta @@ -438,7 +438,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Rahakoti krüpteerimise salafraasi muutmine - + &Debug window &Debugimise aken @@ -448,23 +448,23 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Ava debugimise ja diagnostika konsool - + &Verify message... &Kontrolli sõnumit... - - + + Bitcoin Bitcoin - + Wallet Rahakott - + &Send &Saada @@ -509,12 +509,12 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Kinnita sõnumid kindlustamaks et need allkirjastati määratud Bitcoini aadressiga - + &File &Fail - + &Settings &Seaded @@ -529,12 +529,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Vahelehe tööriistariba - - Actions toolbar - Tegevuste tööriistariba - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS %n aktiivne ühendus Bitcoini võrku%n aktiivset ühendust Bitcoini võrku - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Protsessitud %1 (arvutuslikult) tehingu ajaloo blokki %2-st. @@ -575,7 +575,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS %n nädal%n nädalat - + %1 behind %1 maas @@ -590,7 +590,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Peale seda ei ole tehingud veel nähtavad. - + Error Tõrge @@ -605,22 +605,22 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Informatsioon - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? See tehing ületab mahupiirangu. Saatmine on võimalik %1, node'idele ning võrgustiku toetuseks, makstava lisatasu eest. Kas nõustud lisatasuga? - + Up to date Ajakohane - + Catching up... Jõuan... - + Confirm transaction fee Kinnita tehingu tasu @@ -669,7 +669,7 @@ Aadress: %4⏎ Rahakott on <b>krüpteeritud</b> ning hetkel <b>suletud</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ilmnes kriitiline tõrge. Bitcoin suletakse turvakaalutluste tõttu. @@ -677,7 +677,7 @@ Aadress: %4⏎ ClientModel - + Network Alert Võrgu Häire @@ -1058,7 +1058,7 @@ Aadress: %4⏎ Kinnitamata tehingud kokku. Ei kajastu hetke jäägis - + out of sync sünkimata @@ -1644,6 +1644,19 @@ Aadress: %4⏎ Sõnum kontrollitud. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2121,7 +2134,12 @@ Aadress: %4⏎ WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet Varundatud Rahakott diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index a13d00623..19cc33362 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -73,7 +73,7 @@ This product includes software developed by the OpenSSL Project for use in the O Show &QR Code - + Erakutsi &QR kodea @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... Sarearekin sinkronizatzen... - + &Overview &Gainbegiratu @@ -350,7 +360,7 @@ This product includes software developed by the OpenSSL Project for use in the O E&xit - + Irten @@ -365,12 +375,12 @@ This product includes software developed by the OpenSSL Project for use in the O About &Qt - + &Qt-ari buruz Show information about Qt - + Erakutsi Bitcoin-i buruzko informazioa @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Esportatu... - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Aldatu zorroa enkriptatzeko erabilitako pasahitza - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Artxiboa - + &Settings &Ezarpenak @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Fitxen tresna-barra - - Actions toolbar - Ekintzak tresna-barra - - - + [testnet] [testnet] @@ -542,10 +537,15 @@ This product includes software developed by the OpenSSL Project for use in the O %n active connection(s) to Bitcoin network - + Konexio aktibo %n Bitcoin-en sarera%n konexio aktibo Bitcoin-en sarera - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Egunean - + Catching up... Eguneratzen... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 Zorroa <b>enkriptatuta</b> eta <b>blokeatuta</b> dago une honetan - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 Oraindik konfirmatu gabe daudenez, uneko saldoab kontatu gabe dagoen transakzio kopurua - + out of sync @@ -1079,22 +1079,22 @@ Address: %4 Amount: - + Kopurua Label: - + &Etiketa: Message: - + Mezua &Save As... - + Gorde honela... @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2047,7 +2060,7 @@ Address: %4 Export Transaction Data - + Transakzioaren xehetasunak @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet @@ -2148,7 +2166,7 @@ Address: %4 Bitcoin version - + Botcoin bertsioa @@ -2163,37 +2181,37 @@ Address: %4 List commands - + Komandoen lista Get help for a command - + Laguntza komando batean Options: - + Aukerak Specify configuration file (default: bitcoin.conf) - + Ezarpen fitxategia aukeratu (berezkoa: bitcoin.conf) Specify pid file (default: bitcoind.pid) - + pid fitxategia aukeratu (berezkoa: bitcoind.pid) Generate coins - + &Jaso txanponak Don't generate coins - + Ez jaso txanponik @@ -2718,7 +2736,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. This help message - + Laguntza mezu hau @@ -2843,12 +2861,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescanning... - + Birbilatzen... Done loading - + Zamaketa amaitua diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index e2ee3681c..1439eeda8 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O ⏎ ⏎ این نسخه نرم افزار آزمایشی است⏎ ⏎ نرم افزار تحت لیسانس MIT/X11 منتشر شده است. به فایل coping یا آدرس http://www.opensource.org/licenses/mit-license.php. مراجعه شود⏎ ⏎ این محصول شامل نرم افزاری است که با OpenSSL برای استفاده از OpenSSL Toolkit (http://www.openssl.org/) و نرم افزار نوشته شده توسط اریک یانگ (eay@cryptsoft.com ) و UPnP توسط توماس برنارد طراحی شده است. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O آدرس جدید - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. این آدرسها، آدرسهای bitcoin شما برای دریافت وجوه هستند. شما ممکن است آدرسهای متفاوت را به هر گیرنده اختصاص دهید که بتوانید مواردی که پرداخت می کنید را پیگیری نمایید @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O آدرس انتخاب شده در سیستم تخته رسم گیره دا حذف - + + Export the data in the current tab to a file + داده ها نوارِ جاری را به فایل انتقال دهید + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address یک پیام را برای حصول اطمینان از ورود به سیستم با آدرس bitcoin مشخص، شناسایی کنید @@ -309,17 +319,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... امضا و پیام - + Synchronizing with network... همگام سازی با شبکه ... - + &Overview بررسی اجمالی @@ -394,7 +404,7 @@ This product includes software developed by the OpenSSL Project for use in the O تغییر Passphrase - + Importing blocks from disk... @@ -404,12 +414,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &;صادرات - - - + Send coins to a Bitcoin address سکه ها را به آدرس bitocin ارسال کن @@ -419,12 +424,7 @@ This product includes software developed by the OpenSSL Project for use in the O انتخابهای پیکربندی را برای bitcoin اصلاح کن - - Export the data in the current tab to a file - داده ها نوارِ جاری را به فایل انتقال دهید - - - + Backup wallet to another location نسخه پیشتیبان wallet را به محل دیگر انتقال دهید @@ -434,7 +434,7 @@ This product includes software developed by the OpenSSL Project for use in the O عبارت عبور رمز گشایی پنجره تغییر کنید - + &Debug window اشکال زدایی از صفحه @@ -444,23 +444,23 @@ This product includes software developed by the OpenSSL Project for use in the O کنسول اشکال زدایی و تشخیص را باز کنید - + &Verify message... بازبینی پیام - - + + Bitcoin یت کویین - + Wallet wallet - + &Send @@ -505,12 +505,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File فایل - + &Settings تنظیمات @@ -525,12 +525,7 @@ This product includes software developed by the OpenSSL Project for use in the O نوار ابزار زبانه ها - - Actions toolbar - نوار ابزار عملیت - - - + [testnet] آزمایش شبکه @@ -546,7 +541,12 @@ This product includes software developed by the OpenSSL Project for use in the O در صد ارتباطات فعال بیتکویین با شبکه %n - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -571,7 +571,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -586,7 +586,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -601,22 +601,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date تا تاریخ - + Catching up... ابتلا به بالا - + Confirm transaction fee هزینه تراکنش را تایید کنید @@ -665,7 +665,7 @@ Address: %4 زمایش شبکه - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. خطا روی داده است. Bitcoin نمی تواند بدون مشکل ادامه دهد و باید بسته شود @@ -673,7 +673,7 @@ Address: %4 ClientModel - + Network Alert پیام شبکه @@ -1054,7 +1054,7 @@ Address: %4 تعداد معاملات که تایید شده ولی هنوز در تزار جاری شما بر شمار نرفته است - + out of sync روزآمد نشده @@ -1640,6 +1640,19 @@ Address: %4 پیام شناسایی شد + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + آزمایش شبکه + + TransactionDesc @@ -2120,7 +2133,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + داده ها نوارِ جاری را به فایل انتقال دهید + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index f7a6ff53f..f53b6e054 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O و آدرس جدید - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + صدور داده نوار جاری به یک فایل + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... امضا و پیام - + Synchronizing with network... به روز رسانی با شبکه... - + &Overview و بازبینی @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O تغییر رمز/پَس فرِیز - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - و صدور - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O اصلاح انتخابها برای پیکربندی Bitcoin - - Export the data in the current tab to a file - صدور داده نوار جاری به یک فایل - - - + Backup wallet to another location گرفتن نسخه پیشتیبان در آدرسی دیگر @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O رمز مربوط به رمزگذاریِ wallet را تغییر دهید - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin bitcoin - + Wallet کیف پول - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File و فایل - + &Settings و تنظیمات @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O نوار ابزار - - Actions toolbar - نوار عملیات - - - + [testnet] [testnet] @@ -546,7 +541,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n ارتباط فعال به شبکه Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -571,7 +571,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -586,7 +586,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -601,22 +601,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date روزآمد - + Catching up... در حال روزآمد سازی.. - + Confirm transaction fee @@ -663,7 +663,7 @@ Address: %4 wallet رمزگذاری شد و در حال حاضر قفل است - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -671,7 +671,7 @@ Address: %4 ClientModel - + Network Alert هشدار شبکه @@ -1052,7 +1052,7 @@ Address: %4 تعداد تراکنشهایی که نیاز به تایید دارند و هنوز در مانده حساب جاری شما به حساب نیامده اند - + out of sync خارج از روزآمد سازی @@ -1639,6 +1639,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2116,7 +2129,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + صدور داده نوار جاری به یک فایل + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index 491e02bb1..d38c21e8d 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -29,14 +29,14 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o - + Copyright Tekijänoikeus - 2009-%1 The Bitcoin developers - 2009-%1 Bittirahan kehittäjät + The Bitcoin developers + @@ -67,7 +67,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o &Uusi Osoite - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Nämä ovat Bitcoin-osoitteesi joihin voit vastaanottaa maksuja. Voit haluta antaa jokaiselle maksajalle omansa, että pystyt seuraamaan keneltä maksut tulevat. @@ -97,7 +97,17 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Poista valittu osoite listalta - + + Export the data in the current tab to a file + Vie auki olevan välilehden tiedot tiedostoon + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Tarkista viestin allekirjoitus varmistaaksesi, että se allekirjoitettiin tietyllä Bitcoin-osoitteella @@ -314,17 +324,17 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o BitcoinGUI - + Sign &message... &Allekirjoita viesti... - + Synchronizing with network... Synkronoidaan verkon kanssa... - + &Overview &Yleisnäkymä @@ -399,7 +409,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o &Vaihda Tunnuslause... - + Importing blocks from disk... Tuodaan lohkoja levyltä @@ -409,12 +419,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Ladataan lohkoindeksiä... - - &Export... - &Vie... - - - + Send coins to a Bitcoin address Lähetä kolikoita Bitcoin-osoitteeseen @@ -424,12 +429,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Muuta Bitcoinin konfiguraatioasetuksia - - Export the data in the current tab to a file - Vie auki olevan välilehden tiedot tiedostoon - - - + Backup wallet to another location Varmuuskopioi lompakko toiseen sijaintiin @@ -439,7 +439,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Vaihda lompakon salaukseen käytettävä tunnuslause - + &Debug window &Testausikkuna @@ -449,23 +449,23 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Avaa debuggaus- ja diagnostiikkakonsoli - + &Verify message... Varmista &viesti... - - + + Bitcoin Bitcoin - + Wallet Lompakko - + &Send &Lähetä @@ -510,12 +510,12 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Varmista, että viestisi on allekirjoitettu määritetyllä Bitcoin -osoitteella - + &File &Tiedosto - + &Settings &Asetukset @@ -530,12 +530,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Välilehtipalkki - - Actions toolbar - Toimintopalkki - - - + [testnet] [testnet] @@ -551,7 +546,12 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o %n aktiivinen yhteys Bitcoin-verkkoon%n aktiivista yhteyttä Bitcoin-verkkoon - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -576,7 +576,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o %n viikko%n viikkoa - + %1 behind @@ -591,7 +591,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o - + Error Virhe @@ -606,22 +606,22 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Tietoa - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Rahansiirtohistoria on ajan tasalla - + Catching up... Saavutetaan verkkoa... - + Confirm transaction fee Vahvista maksukulu @@ -670,7 +670,7 @@ Osoite: %4 Lompakko on <b>salattu</b> ja tällä hetkellä <b>lukittuna</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Peruuttamaton virhe on tapahtunut. Bitcoin ei voi enää jatkaa turvallisesti ja sammutetaan. @@ -678,7 +678,7 @@ Osoite: %4 ClientModel - + Network Alert Verkkohälytys @@ -1059,7 +1059,7 @@ Osoite: %4 Niiden saapuvien rahansiirtojen määrä, joita Bitcoin-verkko ei vielä ole ehtinyt vahvistaa ja siten eivät vielä näy saldossa. - + out of sync Ei ajan tasalla @@ -1645,6 +1645,19 @@ Osoite: %4 Viesti varmistettu. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Osoite: %4 WalletView - + + Export the data in the current tab to a file + Vie auki olevan välilehden tiedot tiedostoon + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index a7d4ee5b6..d0113ff27 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -28,14 +28,14 @@ This product includes software developed by the OpenSSL Project for use in the O Ce produit comprend des fonctionnalités développées par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL (http://www.openssl.org/), un logiciel cryptographique écrit par Eric Young (eay@cryptsoft.com), et des fonctionnalités développées pour le logiciel UPnP écrit par Thomas Bernard. - + Copyright Droit d'auteur - 2009-%1 The Bitcoin developers - 2009-%1 Développeurs de Bitcoin + The Bitcoin developers + Les développeurs Bitcoin @@ -43,7 +43,7 @@ This product includes software developed by the OpenSSL Project for use in the O Address Book - Options interface utilisateur + Carnet d'adresses @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Nouvelle adresse - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Voici vos adresses Bitcoin qui vous permettent de recevoir des paiements. Vous pouvez donner une adresse différente à chaque expéditeur afin de savoir qui vous paye. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O Effacer l'adresse actuellement sélectionnée de la liste - + + Export the data in the current tab to a file + Exporter les données de l'onglet courant vers un fichier + + + + &Export + &Exporter + + + Verify a message to ensure it was signed with a specified Bitcoin address Vérifier un message pour vous assurer qu'il a bien été signé avec l'adresse Bitcoin spécifiée @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Signer un &message... - + Synchronizing with network... Synchronisation avec le réseau… - + &Overview &Vue d'ensemble @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Modifier la phrase de passe... - + Importing blocks from disk... Importation des blocs depuis le disque... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Réindexation des blocs sur le disque... - - &Export... - &Exporter… - - - + Send coins to a Bitcoin address Envoyer des pièces à une adresse Bitcoin @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O Modifier les options de configuration de Bitcoin - - Export the data in the current tab to a file - Exporter les données de l'onglet courant vers un fichier - - - + Backup wallet to another location Sauvegarder le porte-monnaie à un autre emplacement @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O Modifier la phrase de passe utilisée pour le chiffrement du porte-monnaie - + &Debug window Fenêtre de &débogage @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O Ouvrir une console de débogage et de diagnostic - + &Verify message... &Vérifier un message... - - + + Bitcoin Bitcoin - + Wallet Porte-monnaie - + &Send &Envoyer @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O Vérifier les messages pour vous assurer qu'ils ont bien été signés avec les adresses Bitcoin spécifiées - + &File &Fichier - + &Settings &Réglages @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O Barre d'outils des onglets - - Actions toolbar - Barre d'outils des actions - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n connexion active avec le réseau Bitcoin%n connexions actives avec le réseau Bitcoin - + + No block source available... + Aucune source de bloc disponible... + + + Processed %1 of %2 (estimated) blocks of transaction history. %1 blocs sur %2 (estimés) de l'historique des transactions traités. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n semaine%n semaines - + %1 behind %1 en arrière @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O Les transactions après cela ne seront pas encore visibles. - + Error Erreur @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O Information - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Cette transaction dépasse la limite de taille. Vous pouvez quand même l'envoyer en vous acquittant de frais d'un montant de %1 qui iront aux nœuds qui traiteront la transaction et aideront à soutenir le réseau. Voulez-vous payer les frais ? - + Up to date À jour - + Catching up... Rattrapage… - + Confirm transaction fee Confirmer les frais de transaction @@ -670,7 +670,7 @@ Adresse : %4 Le porte-monnaie est <b>chiffré</b> et est actuellement <b>verrouillé</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Une erreur fatale est survenue. Bitcoin ne peut plus continuer à fonctionner de façon sûre et va s'arrêter. @@ -678,7 +678,7 @@ Adresse : %4 ClientModel - + Network Alert Alerte réseau @@ -1059,7 +1059,7 @@ Adresse : %4 Total des transactions qui doivent encore être confirmées et qui ne sont pas prises en compte dans le solde actuel - + out of sync désynchronisé @@ -1645,6 +1645,19 @@ Adresse : %4 Message vérifié. + + SplashScreen + + + The Bitcoin developers + Les développeurs Bitcoin + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Adresse : %4 WalletView - + + Export the data in the current tab to a file + Exporter les données de l'onglet courant vers un fichier + + + Backup Wallet Sauvegarder le porte-monnaie diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index e239b9264..9ad663b57 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -28,13 +28,13 @@ Distribué sous licence MIT/X11, voir le fichier COPYING ou http://www.opensourc Ce produit comprend des logiciels développés par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL (http://www.openssl.org/), un logiciel cryptographique écrit par Eric Young (eay@cryptsoft.com) et un logiciel UPnP écrit par Thomas Bernard. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -66,7 +66,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Ceux-ci sont vos adresses Bitcoin qui vous permettent de recevoir des paiements. Vous pouvez en donner une différente à chaque expédieur afin de savoir qui vous payent. @@ -96,7 +96,17 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -313,17 +323,17 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -398,7 +408,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + Importing blocks from disk... @@ -408,12 +418,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - - &Export... - - - - + Send coins to a Bitcoin address @@ -423,12 +428,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -438,7 +438,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + &Debug window @@ -448,23 +448,23 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -509,12 +509,12 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + &File - + &Settings @@ -529,12 +529,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - - Actions toolbar - - - - + [testnet] @@ -550,7 +545,12 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -575,7 +575,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + %1 behind @@ -590,7 +590,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + Error @@ -605,22 +605,22 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date - + Catching up... - + Confirm transaction fee @@ -666,7 +666,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -674,7 +674,7 @@ Address: %4 ClientModel - + Network Alert @@ -1055,7 +1055,7 @@ Address: %4 - + out of sync @@ -1641,6 +1641,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2118,7 +2131,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts index fdc6b3328..c052af5b1 100644 --- a/src/qt/locale/bitcoin_gu_IN.ts +++ b/src/qt/locale/bitcoin_gu_IN.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File - + &Settings @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Actions toolbar - - - - + [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date - + Catching up... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 0fe26ac1b..63a03bc84 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -28,14 +28,14 @@ This product includes software developed by the OpenSSL Project for use in the O המוצר הזה כולל תוכנה שפותחה ע"י פרויקט OpenSSL לשימוש בתיבת הכלים OpenSSL (http://www.openssl.org/) ותוכנה קריפטוגרפית שנכתבה ע"י אריק יאנג (eay@cryptsoft.com) ותוכנת UPnP שנכתבה ע"י תומס ברנרד. - + Copyright זכויות יוצרים - 2009-%1 The Bitcoin developers - 2009-%1 מפתחי ביטקוין + The Bitcoin developers + @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O כתובת חדשה - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. אלה כתובת הביטקוין שלך עבור קבלת תשלומים. ייתכן ותרצה לתת כתובת שונה לכל שולח כדי שתוכל לעקוב אחר מי משלם לך. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O מחק את הכתובת שנבחרה מהרשימה - + + Export the data in the current tab to a file + יצוא הנתונים בטאב הנוכחי לקובץ + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address אמת הודעה בכדי להבטיח שהיא נחתמה עם כתובת ביטקוין מסוימת. @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... חתום על הודעה - + Synchronizing with network... מסתנכרן עם הרשת... - + &Overview &סקירה @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O שנה סיסמא - + Importing blocks from disk... מייבא בלוקים מהדיסק... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O מחדש את אינדקס הבלוקים בדיסק... - - &Export... - י&צא לקובץ - - - + Send coins to a Bitcoin address שלח מטבעות לכתובת ביטקוין @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O שנה אפשרויות תצורה עבור ביטקוין - - Export the data in the current tab to a file - יצוא הנתונים בטאב הנוכחי לקובץ - - - + Backup wallet to another location גיבוי הארנק למקום אחר @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O שנה את הסיסמה להצפנת הארנק - + &Debug window חלון ניפוי @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O פתח את לוח הבקרה לאבחון וניפוי - + &Verify message... אמת הודעה... - - + + Bitcoin ביטקוין - + Wallet ארנק - + &Send ושלח @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O אמת הודעות כדי להבטיח שהן נחתמו עם כתובת ביטקוין מסוימות - + &File &קובץ - + &Settings ה&גדרות @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O סרגל כלים טאבים - - Actions toolbar - סרגל כלים פעולות - - - + [testnet] [רשת-בדיקה] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O חיבור פעיל אחד לרשת הביטקוין%n חיבורים פעילים לרשת הביטקוין - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. 1% מתוך 2% (משוער) בלוקים של הסטוריית פעולת עובדו @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n שבוע%n שבועות - + %1 behind 1% מאחור @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O לאחר זאת פעולות נספות טרם יהיו גלויות - + Error שגיאה @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O מידע - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? פעולה זו חורגת מגבולות הגודל. עדיין באפשרותך לשלוח אותה תמורת עמלה של %1, המיועדת לצמתים שמעבדים את הפעולה שלך ועוזרת לתמוך ברשת. האם ברצונך לשלם את העמלה? - + Up to date עדכני - + Catching up... מתעדכן... - + Confirm transaction fee אשר עמלת פעולה @@ -669,7 +669,7 @@ Address: %4 הארנק <b>מוצפן</b> וכרגע <b>נעול</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. שגיאה סופנית אירעה. ביטקוין אינו יכול להמשיך לפעול בבטחה ולכן ייסגר. @@ -677,7 +677,7 @@ Address: %4 ClientModel - + Network Alert אזעקת רשת @@ -1058,7 +1058,7 @@ Address: %4 הסכום הכולל של פעולות שטרם אושרו, ועוד אינן נספרות בחישוב היתרה הנוכחית - + out of sync לא מסונכרן @@ -1644,6 +1644,19 @@ Address: %4 ההודעה אומתה. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [רשת-בדיקה] + + TransactionDesc @@ -2121,7 +2134,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + יצוא הנתונים בטאב הנוכחי לקובץ + + + Backup Wallet גבה ארנק diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index 42282f564..ecdb3405e 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright कापीराइट - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &नया पता - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... नेटवर्क से समकालिक (मिल) रहा है ... - + &Overview &विवरण @@ -394,7 +404,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -404,12 +414,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &निर्यात - - - + Send coins to a Bitcoin address @@ -419,12 +424,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -434,7 +434,7 @@ This product includes software developed by the OpenSSL Project for use in the O पहचान शब्द/अक्षर जो वॉलेट एनक्रिपशन के लिए इस्तेमाल किया है उसे बदलिए! - + &Debug window @@ -444,23 +444,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin बीटकोइन - + Wallet वॉलेट - + &Send @@ -505,12 +505,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &फाइल - + &Settings &सेट्टिंग्स @@ -525,12 +525,7 @@ This product includes software developed by the OpenSSL Project for use in the O टैबस टूलबार - - Actions toolbar - कार्य टूलबार - - - + [testnet] [टेस्टनेट] @@ -546,7 +541,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n सक्रिया संपर्क बीटकोइन नेटवर्क से%n सक्रिया संपर्क बीटकोइन नेटवर्क से - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -571,7 +571,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n हफ़्ता%n हफ्ते - + %1 behind %1 पीछे @@ -586,7 +586,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error भूल @@ -601,22 +601,22 @@ This product includes software developed by the OpenSSL Project for use in the O जानकारी - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date नवीनतम - + Catching up... - + Confirm transaction fee @@ -665,7 +665,7 @@ Address: %4 वॉलेट एन्क्रिप्टेड है तथा अभी लॉक्ड है - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -673,7 +673,7 @@ Address: %4 ClientModel - + Network Alert @@ -1054,7 +1054,7 @@ Address: %4 लेन देन की पुष्टि अभी नहीं हुई है, इसलिए इन्हें अभी मोजुदा बैलेंस में गिना नहीं गया है| - + out of sync @@ -1641,6 +1641,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2118,7 +2131,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet बैकप वॉलेट diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index c11fd7008..fb26af366 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -5,7 +5,7 @@ About Bitcoin - O Bitcoinu + O Bitcoin-u @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Nova adresa - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Ovo su vaše Bitcoin adrese za primanje isplate. Možda želite dati drukčiju adresu svakom primatelju tako da možete pratiti tko je platio. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + Izvoz podataka iz trenutnog taba u datoteku + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Potpišite poruku... - + Synchronizing with network... Usklađivanje s mrežom ... - + &Overview &Pregled @@ -393,22 +403,17 @@ This product includes software developed by the OpenSSL Project for use in the O &Promijena lozinke... - + Importing blocks from disk... - + Importiranje blokova sa diska... Reindexing blocks on disk... - + Re-indeksiranje blokova na disku... - - &Export... - &Izvoz... - - - + Send coins to a Bitcoin address Slanje novca na bitcoin adresu @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O Promijeni postavke konfiguracije za bitcoin - - Export the data in the current tab to a file - Izvoz podataka iz trenutnog taba u datoteku - - - + Backup wallet to another location Napravite sigurnosnu kopiju novčanika na drugoj lokaciji @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Promijenite lozinku za šifriranje novčanika - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin Bitcoin - + Wallet Novčanik - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Datoteka - + &Settings &Konfiguracija @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Traka kartica - - Actions toolbar - Traka akcija - - - + [testnet] [testnet] @@ -545,14 +540,19 @@ This product includes software developed by the OpenSSL Project for use in the O %n aktivna veza na Bitcoin mrežu%n aktivne veze na Bitcoin mrežu%n aktivnih veza na Bitcoin mrežu - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Processed %1 blocks of transaction history. - + Obrađeno %1 blokova povijesti transakcije. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error Greška @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Ažurno - + Catching up... Ažuriranje... - + Confirm transaction fee @@ -665,7 +665,7 @@ Adresa:%4 Novčanik je <b>šifriran</b> i trenutno <b>zaključan</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -673,7 +673,7 @@ Adresa:%4 ClientModel - + Network Alert @@ -1054,7 +1054,7 @@ Adresa:%4 Ukupni iznos transakcija koje tek trebaju biti potvrđene, i još uvijek nisu uračunate u trenutni saldo - + out of sync @@ -1185,22 +1185,22 @@ Adresa:%4 Block chain - + Lanac blokova Current number of blocks - + Trenutni broj blokova Estimated total blocks - + Procjenjeni ukupni broj blokova Last block time - + Posljednje vrijeme bloka @@ -1640,6 +1640,19 @@ Adresa:%4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2117,7 +2130,12 @@ Adresa:%4 WalletView - + + Export the data in the current tab to a file + Izvoz podataka iz trenutnog taba u datoteku + + + Backup Wallet @@ -2372,7 +2390,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Block creation options: - + Opcije za kreiranje bloka: @@ -2527,7 +2545,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Imports blocks from external blk000??.dat file - + Importiraj blokove sa vanjskog blk000??.dat fajla @@ -2557,7 +2575,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Only accept block chain matching built-in checkpoints (default: 1) - + Prihvati samo lance blokova koji se podudaraju sa ugrađenim checkpoint-ovima (default: 1) @@ -2602,12 +2620,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Set maximum block size in bytes (default: 250000) - + Podesite maksimalnu veličinu bloka u bajtovima (default: 250000) Set minimum block size in bytes (default: 0) - + Podesite minimalnu veličinu bloka u bajtovima (default: 0) @@ -2682,7 +2700,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Execute command when the best block changes (%s in cmd is replaced by block hash) - + Izvršite naredbu kada se najbolji blok promjeni (%s u cmd je zamjenjen sa block hash) diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index 578eaad17..5e885b0c2 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -27,13 +27,13 @@ MIT/X11 szoftverlicenc alatt kiadva, lásd a mellékelt fájlt COPYING vagy http Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (http://www.openssl.org/) és kriptográfiai szoftvertben való felhasználásra, írta Eric Young (eay@cryptsoft.com) és UPnP szoftver, írta Thomas Bernard. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -65,7 +65,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt &Új cím - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Ezekkel a Bitcoin-címekkel fogadhatod kifizetéseket. Érdemes lehet minden egyes kifizető számára külön címet létrehozni, hogy könnyebben nyomon követhesd, kitől kaptál már pénzt. @@ -95,7 +95,17 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt - + + Export the data in the current tab to a file + Jelenlegi nézet exportálása fájlba + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Üzenet ellenőrzése, hogy valóban a megjelölt Bitcoin címekkel van-e aláírva. @@ -312,17 +322,17 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt BitcoinGUI - + Sign &message... Üzenet aláírása... - + Synchronizing with network... Szinkronizálás a hálózattal... - + &Overview &Áttekintés @@ -397,7 +407,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Jelszó &megváltoztatása... - + Importing blocks from disk... A blokkok importálása lemezről... @@ -407,12 +417,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt A blokkok lemezen történő ujraindexelése... - - &Export... - &Exportálás... - - - + Send coins to a Bitcoin address Érmék küldése megadott címre @@ -422,12 +427,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Bitcoin konfigurációs opciók - - Export the data in the current tab to a file - Jelenlegi nézet exportálása fájlba - - - + Backup wallet to another location Biztonsági másolat készítése a Tárcáról egy másik helyre @@ -437,7 +437,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Tárcakódoló jelszó megváltoztatása - + &Debug window &Debug ablak @@ -447,23 +447,23 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Hibakereső és diagnosztikai konzol megnyitása - + &Verify message... Üzenet &valódiságának ellenőrzése - - + + Bitcoin Bitcoin - + Wallet Tárca - + &Send @@ -508,12 +508,12 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Annak ellenőrzése, hogy az üzenetek valóban a megjelölt Bitcoin címekkel vannak-e alaírva - + &File &Fájl - + &Settings &Beállítások @@ -528,12 +528,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Fül eszköztár - - Actions toolbar - Parancsok eszköztár - - - + [testnet] [teszthálózat] @@ -549,7 +544,12 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt %n aktív kapcsolat a Bitcoin-hálózattal%n aktív kapcsolat a Bitcoin-hálózattal - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -574,7 +574,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt - + %1 behind @@ -589,7 +589,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt - + Error @@ -604,22 +604,22 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Naprakész - + Catching up... Frissítés... - + Confirm transaction fee Tranzakciós díj jóváhagyása @@ -669,7 +669,7 @@ Cím: %4 Tárca <b>kódolva</b> és jelenleg <b>zárva</b>. - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -677,7 +677,7 @@ Cím: %4 ClientModel - + Network Alert @@ -1059,7 +1059,7 @@ Cím: %4 Még megerősítésre váró, a jelenlegi egyenlegbe be nem számított tranzakciók - + out of sync Nincs szinkronban. @@ -1646,6 +1646,19 @@ Cím: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [teszthálózat] + + TransactionDesc @@ -2123,7 +2136,12 @@ Cím: %4 WalletView - + + Export the data in the current tab to a file + Jelenlegi nézet exportálása fájlba + + + Backup Wallet Biztonsági másolat készítése a Tárcáról diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index 64efbd982..15e154e0b 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -28,14 +28,14 @@ Distribuito sotto la licenza software MIT/X11, vedi il file COPYING incluso oppu Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso del Toolkit OpenSSL (http://www.openssl.org/), software crittografico scritto da Eric Young (eay@cryptsoft.com) e software UPnP scritto da Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Gli sviluppatori di Bitcoin + The Bitcoin developers + Sviluppatori di Bitcoin @@ -66,7 +66,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso &Nuovo indirizzo - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per tenere così traccia di chi ti sta pagando. @@ -96,7 +96,17 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Cancella l'indirizzo attualmente selezionato dalla lista - + + Export the data in the current tab to a file + Esporta i dati nella tabella corrente su un file + + + + &Export + &Esporta... + + + Verify a message to ensure it was signed with a specified Bitcoin address Verifica un messaggio per accertarsi che sia firmato con un indirizzo Bitcoin specifico @@ -313,17 +323,17 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso BitcoinGUI - + Sign &message... Firma il &messaggio... - + Synchronizing with network... Sto sincronizzando con la rete... - + &Overview &Sintesi @@ -398,7 +408,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso &Cambia la passphrase... - + Importing blocks from disk... Importa blocchi dal disco... @@ -408,12 +418,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Re-indicizzazione blocchi su disco... - - &Export... - &Esporta... - - - + Send coins to a Bitcoin address Invia monete ad un indirizzo bitcoin @@ -423,12 +428,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Modifica configurazione opzioni per bitcoin - - Export the data in the current tab to a file - Esporta i dati nella tabella corrente su un file - - - + Backup wallet to another location Backup portamonete in un'altra locazione @@ -438,7 +438,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Cambia la passphrase per la cifratura del portamonete - + &Debug window Finestra &Debug @@ -448,35 +448,35 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Apri la console di degugging e diagnostica - + &Verify message... &Verifica messaggio... - - + + Bitcoin Bitcoin - + Wallet Portamonete - + &Send &Spedisci &Receive - + &Ricevi &Addresses - + &Indirizzi @@ -509,12 +509,12 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Verifica i messaggi per accertarsi che siano stati firmati con gli indirizzi Bitcoin specificati - + &File &File - + &Settings &Impostazioni @@ -529,12 +529,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Barra degli strumenti "Tabs" - - Actions toolbar - Barra degli strumenti "Azioni" - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso %n connessione attiva alla rete Bitcoin%n connessioni attive alla rete Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Processati %1 di %2 (circa) blocchi della cronologia transazioni. @@ -575,7 +575,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso %n settimana%n settimane - + %1 behind @@ -590,7 +590,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso - + Error Errore @@ -605,22 +605,22 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Informazione - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Questa transazione è superiore al limite di dimensione. È comunque possibile inviarla con una commissione di %1, che va ai nodi che processano la tua transazione e contribuisce a sostenere la rete. Vuoi pagare la commissione? - + Up to date Aggiornato - + Catching up... In aggiornamento... - + Confirm transaction fee Conferma compenso transazione @@ -671,7 +671,7 @@ Indirizzo: %4 Il portamonete è <b>cifrato</b> e attualmente <b>bloccato</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Riscontrato un errore irreversibile. Bitcoin non può più continuare in sicurezza e verrà terminato. @@ -679,7 +679,7 @@ Indirizzo: %4 ClientModel - + Network Alert Avviso di rete @@ -1061,7 +1061,7 @@ Indirizzo: %4 Totale delle transazioni in corso di conferma, che non sono ancora incluse nel saldo attuale - + out of sync fuori sincrono @@ -1647,6 +1647,19 @@ Indirizzo: %4 Messaggio verificato. + + SplashScreen + + + The Bitcoin developers + Sviluppatori di Bitcoin + + + + [testnet] + [testnet] + + TransactionDesc @@ -2124,7 +2137,12 @@ Indirizzo: %4 WalletView - + + Export the data in the current tab to a file + Esporta i dati nella tabella corrente su un file + + + Backup Wallet @@ -2136,7 +2154,7 @@ Indirizzo: %4 Backup Failed - + Backup fallito @@ -2401,7 +2419,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Corrupted block database detected - + Rilevato database blocchi corrotto @@ -2411,7 +2429,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Do you want to rebuild the block database now? - + Vuoi ricostruire ora il database dei blocchi? @@ -2431,7 +2449,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error opening block database - + Errore caricamento database blocchi diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index bb785f767..da4c99be8 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... ネットワークと同期化中。。。 - + &Overview &概観 @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &輸出。。。 - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O 財布の暗号化のためのパスフレーズを変わる - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &ファイル - + &Settings &設定 @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O タブツールバー - - Actions toolbar - アクションツールバー - - - + [testnet] [テストネット] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date 新しいのバージョンが無し - + Catching up... 追いつく中。。。 - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 財布は<b>暗号化とロックです</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index 80712275b..64c26ff43 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -27,14 +27,14 @@ Distributum sub MIT/X11 licentia programmatum, vide comitantem plicam COPYING ve Hoc productum continet programmata composita ab OpenSSL Project pro utendo in OpenSSL Toolkit (http://www.openssl.org/) et programmata cifrarum scripta ab Eric Young (eay@cryptsoft.com) et UPnP programmata scripta ab Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Bitcoin curatores + The Bitcoin developers + Bitcoin curatores @@ -65,7 +65,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op &Nova Inscriptio - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Haec sunt inscriptiones Bitcoin tuae pro accipendo pensitationes. Cupias variam ad quemque mittentem dare ut melius scias quem tibi pensare. @@ -95,7 +95,17 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Dele active selectam inscriptionem ex enumeratione - + + Export the data in the current tab to a file + Exporta data in hac tabella in plicam + + + + &Export + &Exporta + + + Verify a message to ensure it was signed with a specified Bitcoin address Verifica nuntium ut cures signatum esse cum specificata inscriptione Bitcoin @@ -112,7 +122,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - + Hae sunt inscriptiones mittendi pensitationes. Semper inspice quantitatem et inscriptionem accipiendi antequam nummos mittis. @@ -312,17 +322,17 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op BitcoinGUI - + Sign &message... Signa &nuntium... - + Synchronizing with network... Synchronizans cum rete... - + &Overview &Summarium @@ -397,7 +407,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op &Muta tesseram... - + Importing blocks from disk... Importans frusta ab disco... @@ -407,12 +417,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Recreans indicem frustorum in disco... - - &Export... - &Exporta... - - - + Send coins to a Bitcoin address Mitte nummos ad inscriptionem Bitcoin @@ -422,12 +427,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Muta configurationis optiones pro Bitcoin - - Export the data in the current tab to a file - Exporta data in activa tabella ad plicam - - - + Backup wallet to another location Conserva cassidile in locum alium @@ -437,7 +437,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Muta tesseram utam pro cassidilis cifrando - + &Debug window Fenestra &Debug @@ -447,23 +447,23 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Aperi terminalem debug et diagnosticalem - + &Verify message... &Verifica nuntium... - - + + Bitcoin Bitcoin - + Wallet Cassidile - + &Send &Mitte @@ -508,12 +508,12 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Verifica nuntios ut certus sis eos signatos esse cum specificatis inscriptionibus Bitcoin - + &File &Plica - + &Settings &Configuratio @@ -528,12 +528,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Tabella instrumentorum "Tabs" - - Actions toolbar - Tabella instrumentorum "Actiones" - - - + [testnet] [testnet] @@ -549,7 +544,12 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op %n activa conexio ad rete Bitcoin%n activae conexiones ad rete Bitcoin - + + No block source available... + Nulla fons frustorum absens... + + + Processed %1 of %2 (estimated) blocks of transaction history. Perfecta %1 de %2 (aestimato) frusta historiae transactionum. @@ -574,7 +574,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op %n hebdomas%n hebdomades - + %1 behind %1 post @@ -589,7 +589,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Transactiones post hoc nondum visibiles erunt. - + Error Error @@ -604,22 +604,22 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Informatio - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Haec transactio maior est quam limen magnitudinis. Adhuc potes id mittere mercede %1, quae it nodis qui procedunt tuam transactionem et adiuvat sustinere rete. Visne mercedem solvere? - + Up to date Recentissimo - + Catching up... Persequens... - + Confirm transaction fee Confirma mercedem transactionis @@ -669,7 +669,7 @@ Inscriptio: %4 Cassidile <b>cifratum</b> est et iam nunc <b>seratum</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Error fatalis accidit. Bitcoin nondum pergere tute potest, et exibit. @@ -677,7 +677,7 @@ Inscriptio: %4 ClientModel - + Network Alert Monitio Retis @@ -1058,7 +1058,7 @@ Inscriptio: %4 Totali nummi transactionum quae adhuc confirmandae sunt, et nondum afficiunt pendendum - + out of sync non synchronizato @@ -1644,6 +1644,19 @@ Inscriptio: %4 Nuntius verificatus. + + SplashScreen + + + The Bitcoin developers + Bitcoin curatores + + + + [testnet] + [testnet] + + TransactionDesc @@ -2121,7 +2134,12 @@ Inscriptio: %4 WalletView - + + Export the data in the current tab to a file + Exporta data in hac tabella in plicam + + + Backup Wallet Conserva cassidile @@ -2526,7 +2544,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Set the number of threads to service RPC calls (default: 4) - + Constitue numerum filorum ad tractandum RPC postulationes (praedefinitum: 4) diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 65f987000..d46baa341 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -27,13 +27,13 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. Šiame produkte yra OpenSSL projekto kuriamas OpenSSL Toolkit (http://www.openssl.org/), Eric Young parašyta kriptografinė programinė įranga bei Thomas Bernard sukurta UPnP programinė įranga. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -65,7 +65,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. &Naujas adresas - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Tai yra jūsų Bitcoin adresai mokėjimų gavimui. Galite duoti skirtingus adresus atskiriems siuntėjams, kad galėtumėte sekti, kas jums moka. @@ -95,7 +95,17 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Patikrinkite žinutę, jog įsitikintumėte, kad ją pasirašė nurodytas Bitcoin adresas @@ -312,17 +322,17 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. BitcoinGUI - + Sign &message... Pasirašyti ži&nutę... - + Synchronizing with network... Sinchronizavimas su tinklu ... - + &Overview &Apžvalga @@ -397,7 +407,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. &Keisti slaptafrazę... - + Importing blocks from disk... @@ -407,12 +417,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - - &Export... - &Eksportuoti... - - - + Send coins to a Bitcoin address Siųsti monetas Bitcoin adresui @@ -422,12 +427,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. Keisti bitcoin konfigūracijos galimybes - - Export the data in the current tab to a file - - - - + Backup wallet to another location Daryti piniginės atsarginę kopiją @@ -437,7 +437,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. Pakeisti slaptafrazę naudojamą piniginės užšifravimui - + &Debug window &Derinimo langas @@ -447,23 +447,23 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. Atverti derinimo ir diagnostikos konsolę - + &Verify message... &Tikrinti žinutę... - - + + Bitcoin Bitcoin - + Wallet Piniginė - + &Send @@ -508,12 +508,12 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - + &File &Failas - + &Settings &Nustatymai @@ -528,12 +528,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. Kortelių įrankinė - - Actions toolbar - Veiksmų įrankinė - - - + [testnet] [testavimotinklas] @@ -549,7 +544,12 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. %n Bitcoin tinklo aktyvus ryšys%n Bitcoin tinklo aktyvūs ryšiai%n Bitcoin tinklo aktyvūs ryšiai - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -574,7 +574,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - + %1 behind @@ -589,7 +589,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - + Error @@ -604,22 +604,22 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Atnaujinta - + Catching up... Vejamasi... - + Confirm transaction fee Patvirtinti sandorio mokestį @@ -668,7 +668,7 @@ Adresas: %4 Piniginė <b>užšifruota</b> ir šiuo metu <b>užrakinta</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -676,7 +676,7 @@ Adresas: %4 ClientModel - + Network Alert Tinklo įspėjimas @@ -1057,7 +1057,7 @@ Adresas: %4 Iš viso sandorių, įskaitant tuos kurie dar turi būti patvirtinti, ir jie dar nėra įskaičiuotii į einamosios sąskaitos balansą - + out of sync @@ -1643,6 +1643,19 @@ Adresas: %4 Žinutė patikrinta. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testavimotinklas] + + TransactionDesc @@ -2120,7 +2133,12 @@ Adresas: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index bd0158277..53f36523f 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Jauna adrese - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Parakstīt &ziņojumu... - + Synchronizing with network... Sinhronizācija ar tīklu... - + &Overview &Pārskats @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Mainīt paroli - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Eksportēt... - - - + Send coins to a Bitcoin address Nosūtīt bitkoinus uz Bitcoin adresi @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O Mainīt Bitcoin konfigurācijas uzstādījumus - - Export the data in the current tab to a file - Datus no tekošā ieliktņa eksportēt uz failu - - - + Backup wallet to another location Izveidot maciņa rezerves kopiju citur @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Mainīt maciņa šifrēšanas paroli - + &Debug window &Debug logs @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O Atvērt atkļūdošanas un diagnostikas konsoli - + &Verify message... &Pārbaudīt ziņojumu... - - + + Bitcoin - + Wallet Maciņš - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Fails - + &Settings &Uzstādījumi @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Ciļņu rīkjosla - - Actions toolbar - Darbību rīkjosla - - - + [testnet] [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n aktīvu savienojumu ar Bitcoin tīklu%n aktīvs savienojums ar Bitcoin tīklu%n aktīvu savienojumu as Bitcoin tīklu - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error Kļūda @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Sinhronizēts - + Catching up... Sinhronizējos... - + Confirm transaction fee Apstiprināt transakcijas maksu @@ -665,7 +665,7 @@ Adrese: %4 Maciņš ir <b>šifrēts</b> un pašlaik <b>slēgts</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -673,7 +673,7 @@ Adrese: %4 ClientModel - + Network Alert Tīkla brīdinājums @@ -1054,7 +1054,7 @@ Adrese: %4 Kopējā apstiprināmo transakciju vērtība, vēl nav ieskaitīta kopējā bilancē - + out of sync nav sinhronizēts @@ -1640,6 +1640,19 @@ Adrese: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -2117,7 +2130,12 @@ Adrese: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet Izveidot maciņa rezerves kopiju diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index aadc42e71..6a62cad33 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -28,13 +28,13 @@ Distribuert under MIT/X11 programvarelisensen, se medfølgende fil COPYING eller Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i OpenSSL Toolkit (http://www.openssl.org/) og kryptografisk programvare skrevet av Eric Young (eay@cryptsoft.com) og UPnP programvare skrevet av Thomas Bernard. - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -66,7 +66,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i &Ny Adresse - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Dette er dine Bitcoin-adresser for mottak av betalinger. Du kan gi forskjellige adresser til alle som skal betale deg for å holde bedre oversikt. @@ -96,7 +96,17 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Slett den valgte adressen fra listen. - + + Export the data in the current tab to a file + Eksporter data fra nåværende fane til fil + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Verifiser en melding for å være sikker på at den ble signert av en angitt Bitcoin-adresse @@ -313,17 +323,17 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i BitcoinGUI - + Sign &message... Signer &melding... - + Synchronizing with network... Synkroniserer med nettverk... - + &Overview &Oversikt @@ -398,7 +408,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i &Endre Adgangsfrase... - + Importing blocks from disk... Importere blokker... @@ -408,12 +418,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Re-indekserer blokker på disk... - - &Export... - &Eksporter... - - - + Send coins to a Bitcoin address Send til en Bitcoin-adresse @@ -423,12 +428,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Endre oppsett for Bitcoin - - Export the data in the current tab to a file - Eksporter data fra nåværende fane til fil - - - + Backup wallet to another location Sikkerhetskopiér lommebok til annet sted @@ -438,7 +438,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Endre adgangsfrasen brukt for kryptering av lommebok - + &Debug window &Feilsøkingsvindu @@ -448,23 +448,23 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Åpne konsoll for feilsøk og diagnostikk - + &Verify message... &Verifiser melding... - - + + Bitcoin Bitcoin - + Wallet Lommebok - + &Send &Send @@ -509,12 +509,12 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Bekreft meldinger for å være sikker på at de ble signert av en angitt Bitcoin-adresse - + &File &Fil - + &Settings &Innstillinger @@ -529,12 +529,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Verktøylinje for faner - - Actions toolbar - Verktøylinje for handlinger - - - + [testnet] [testnett] @@ -550,7 +545,12 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i %n aktiv forbindelse til Bitcoin-nettverket%n aktive forbindelser til Bitcoin-nettverket - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -575,7 +575,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i - + %1 behind @@ -590,7 +590,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Transaksjoner etter dette vil ikke være synlige enda. - + Error @@ -605,22 +605,22 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Denne transaksjonen overstiger størrelsesbegrensningen. Du kan likevel sende den med et gebyr på %1, som går til nodene som prosesserer transaksjonen din og støtter nettverket. Vil du betale gebyret? - + Up to date Ajour - + Catching up... Kommer ajour... - + Confirm transaction fee Bekreft transaksjonsgebyr @@ -670,7 +670,7 @@ Adresse: %4 Lommeboken er <b>kryptert</b> og for tiden <b>låst</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. En fatal feil har inntruffet. Det er ikke trygt å fortsette og Bitcoin må derfor avslutte. @@ -678,7 +678,7 @@ Adresse: %4 ClientModel - + Network Alert Nettverksvarsel @@ -1060,7 +1060,7 @@ Adresse: %4 Totalt antall ubekreftede transaksjoner som ikke telles med i saldo enda - + out of sync ute av synk @@ -1646,6 +1646,19 @@ Adresse: %4 Melding verifisert. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnett] + + TransactionDesc @@ -2123,7 +2136,12 @@ Adresse: %4 WalletView - + + Export the data in the current tab to a file + Eksporter data fra nåværende fane til fil + + + Backup Wallet Sikkerhetskopier lommebok diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 52c05c7dc..c059a1f9f 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -28,14 +28,14 @@ Gedistribueerd onder de MIT/X11 software licentie, zie het bijgevoegde bestand C Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in de OpenSSL Toolkit (http://www.openssl.org/) en cryptografische software gemaakt door Eric Young (eay@cryptsoft.com) en UPnP software geschreven door Thomas Bernard. - + Copyright Auteursrecht - 2009-%1 The Bitcoin developers - 2009-%1 De Bitcoinontwikkelaars + The Bitcoin developers + De Bitcoin-ontwikkelaars @@ -66,7 +66,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d &Nieuw Adres - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Dit zijn uw Bitcoinadressen om betalingen mee te ontvangen. U kunt er voor kiezen om een uniek adres aan te maken voor elke afzender. Op deze manier kunt u bijhouden wie al aan u betaald heeft. @@ -96,7 +96,17 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Verwijder het geselecteerde adres van de lijst - + + Export the data in the current tab to a file + Exporteer de data in de huidige tab naar een bestand + + + + &Export + &Exporteer + + + Verify a message to ensure it was signed with a specified Bitcoin address Controleer een bericht om te verifiëren dat het gespecificeerde Bitcoinadres het bericht heeft ondertekend. @@ -313,17 +323,17 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d BitcoinGUI - + Sign &message... &Onderteken bericht... - + Synchronizing with network... Synchroniseren met netwerk... - + &Overview &Overzicht @@ -398,7 +408,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d &Wijzig Wachtwoord - + Importing blocks from disk... Blokken aan het importeren vanaf harde schijf... @@ -408,12 +418,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Bezig met herindexeren van blokken op harde schijf... - - &Export... - &Exporteer... - - - + Send coins to a Bitcoin address Verstuur munten naar een Bitcoinadres @@ -423,12 +428,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Wijzig instellingen van Bitcoin - - Export the data in the current tab to a file - Exporteer de data in de huidige tab naar een bestand - - - + Backup wallet to another location &Backup portemonnee naar een andere locatie @@ -438,7 +438,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Wijzig het wachtwoord voor uw portemonneversleuteling - + &Debug window &Debugscherm @@ -448,23 +448,23 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Open debugging en diagnostische console - + &Verify message... &Verifiëer bericht... - - + + Bitcoin Bitcoin - + Wallet Portemonnee - + &Send &Versturen @@ -509,12 +509,12 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Verifiëer handtekeningen om zeker te zijn dat de berichten zijn ondertekend met de gespecificeerde Bitcoinadressen - + &File &Bestand - + &Settings &Instellingen @@ -529,12 +529,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Tab-werkbalk - - Actions toolbar - Actie-werkbalk - - - + [testnet] [testnetwerk] @@ -550,7 +545,12 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d %n actieve connectie naar Bitcoinnetwerk%n actieve connecties naar Bitcoinnetwerk - + + No block source available... + Geen bron van blokken beschikbaar... + + + Processed %1 of %2 (estimated) blocks of transaction history. %1 van %2 (geschat) blokken van de transactiehistorie verwerkt. @@ -575,7 +575,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d %n week%n weken - + %1 behind %1 achter @@ -590,7 +590,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Transacties na dit moment zullen nu nog niet zichtbaar zijn. - + Error Fout @@ -605,22 +605,22 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Informatie - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Deze transactie overschrijdt de groottelimiet. Om de transactie alsnog te versturen kunt u transactiekosten betalen van %1. Deze transactiekosten gaan naar de nodes die uw transactie verwerken en het helpt op deze manier bij het ondersteunen van het Bitcoinnetwerk. Wilt u de transactiekosten betalen? - + Up to date Bijgewerkt - + Catching up... Aan het bijwerken... - + Confirm transaction fee Bevestig transactiekosten @@ -670,7 +670,7 @@ Adres: %4 Portemonnee is <b>versleuteld</b> en momenteel <b>gesloten</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Er is een fatale fout opgetreden. Bitcoin kan niet meer veilig doorgaan en zal nu afgesloten worden. @@ -678,7 +678,7 @@ Adres: %4 ClientModel - + Network Alert Netwerkwaarschuwing @@ -1059,7 +1059,7 @@ Adres: %4 Totaal van de transacties die nog moeten worden bevestigd en nog niet zijn meegeteld in uw huidige saldo - + out of sync niet gesynchroniseerd @@ -1645,6 +1645,19 @@ Adres: %4 Bericht correct geverifiëerd. + + SplashScreen + + + The Bitcoin developers + De Bitcoin-ontwikkelaars + + + + [testnet] + [testnetwerk] + + TransactionDesc @@ -2122,7 +2135,12 @@ Adres: %4 WalletView - + + Export the data in the current tab to a file + Exporteer de data in de huidige tab naar een bestand + + + Backup Wallet Portomonnee backuppen diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index b74fbdf88..cbe76f6e0 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -28,14 +28,14 @@ Distributed under the MIT/X11 software license, see the accompanying file COPYIN This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - + Copyright Prawo autorskie - 2009-%1 The Bitcoin developers - 2009-%1 deweloperzy Bitcoin + The Bitcoin developers + @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Nowy Adres - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Tutaj znajdują się twoje adresy Bitcoin do odbioru płatności. Możesz nadać oddzielne adresy dla każdego z wysyłających monety, żeby śledzić oddzielnie ich opłaty. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O Usuń zaznaczony adres z listy - + + Export the data in the current tab to a file + Eksportuj dane z aktywnej karty do pliku + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Zweryfikuj wiadomość, aby upewnić się, że została podpisana odpowiednim adresem Bitcoin. @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Podpisz wiado&mość... - + Synchronizing with network... Synchronizacja z siecią... - + &Overview P&odsumowanie @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Zmień hasło... - + Importing blocks from disk... Importowanie bloków z dysku... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Ponowne indeksowanie bloków na dysku... - - &Export... - &Eksportuj... - - - + Send coins to a Bitcoin address Wyślij monety na adres Bitcoin @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O Zmienia opcje konfiguracji bitcoina - - Export the data in the current tab to a file - Eksportuj dane z aktywnej karty do pliku - - - + Backup wallet to another location Zapasowy portfel w innej lokalizacji @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O Zmień hasło użyte do szyfrowania portfela - + &Debug window &Okno debudowania @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O Otwórz konsolę debugowania i diagnostyki - + &Verify message... &Zweryfikuj wiadomość... - - + + Bitcoin Bitcoin - + Wallet Portfel - + &Send Wyślij @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O Zweryfikuj wiadomość, aby upewnić się, że została podpisana odpowiednim adresem Bitcoin. - + &File &Plik - + &Settings P&referencje @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O Pasek zakładek - - Actions toolbar - Pasek akcji - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n aktywne połączenie do sieci Bitcoin%n aktywne połączenia do sieci Bitcoin%n aktywnych połączeń do sieci Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Przetworzono (w przybliżeniu) %1 z %2 bloków historii transakcji. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n tydzień%n tygodni%n tygodni - + %1 behind @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error Błąd @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O Informacja - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Transakcja przekracza limit. Możesz wysłać ją płacąc prowizję %1, która zostaje przekazana do węzłów, które ją prześlą i pomoże wspierać sieć Bitcoin. Czy chcesz zapłacić prowizję? - + Up to date Aktualny - + Catching up... Łapanie bloków... - + Confirm transaction fee Potwierdź prowizję transakcyjną @@ -670,7 +670,7 @@ Adres: %4 Portfel jest <b>zaszyfrowany</b> i obecnie <b>zablokowany</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Błąd krytyczny. Bitcoin nie może kontynuować bezpiecznie więc zostanie zamknięty. @@ -678,7 +678,7 @@ Adres: %4 ClientModel - + Network Alert Sieć Alert @@ -1059,7 +1059,7 @@ Adres: %4 Suma transakcji, które nie zostały jeszcze potwierdzone, i które nie zostały wliczone do twojego obecnego salda - + out of sync desynchronizacja @@ -1645,6 +1645,19 @@ Adres: %4 Wiadomość zweryfikowana. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Adres: %4 WalletView - + + Export the data in the current tab to a file + Eksportuj dane z aktywnej karty do pliku + + + Backup Wallet Kopia Zapasowa Portfela diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 87537f967..de5751c4c 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -28,14 +28,14 @@ Distribuido sob a licença de software MIT/X11, veja o arquivo anexo COPYING ou Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenSSL Toolkit (http://www.openssl.org/), software de criptografia escrito por Eric Young (eay@cryptsoft.com) e sofware UPnP escrito por Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Os desenvolvedores do Bitcoin + The Bitcoin developers + @@ -66,7 +66,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS &Novo endereço - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Estes são os seus endereços Bitcoin para receber pagamentos. Você pode querer enviar um endereço diferente para cada remetente, para acompanhar quem está pagando. @@ -96,7 +96,17 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Excluir os endereços selecionados da lista - + + Export the data in the current tab to a file + Exportar os dados na aba atual para um arquivo + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Verificar mensagem para se assegurar que ela foi assinada pelo dono de um endereço Bitcoin específico. @@ -313,17 +323,17 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS BitcoinGUI - + Sign &message... &Assinar Mensagem... - + Synchronizing with network... Sincronizando com a rede... - + &Overview &Visão geral @@ -398,7 +408,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS &Mudar frase de segurança... - + Importing blocks from disk... Importando blocos do disco... @@ -408,12 +418,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Reindexando blocos no disco... - - &Export... - &Exportar... - - - + Send coins to a Bitcoin address Enviar moedas para um endereço bitcoin @@ -423,12 +428,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Modificar opções de configuração para bitcoin - - Export the data in the current tab to a file - Exportar os dados na aba atual para um arquivo - - - + Backup wallet to another location Fazer cópia de segurança da carteira para uma outra localização @@ -438,7 +438,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Mudar a frase de segurança utilizada na criptografia da carteira - + &Debug window Janela de &Depuração @@ -448,23 +448,23 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Abrir console de depuração e diagnóstico - + &Verify message... &Verificar mensagem... - - + + Bitcoin Bitcoin - + Wallet Carteira - + &Send &Enviar @@ -509,12 +509,12 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Verificar mensagens para se assegurar que elas foram assinadas pelo dono de Endereços Bitcoin específicos - + &File &Arquivo - + &Settings &Configurações @@ -529,12 +529,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Barra de ferramentas - - Actions toolbar - Barra de ações - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS %n conexão ativa na rede Bitcoin%n conexões ativas na rede Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Processado %1 de %2 blocos (estimado) de histórico de transações. @@ -575,7 +575,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS %n semana%n semanas - + %1 behind %1 atrás @@ -590,7 +590,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Transações após isso ainda não estão visíveis. - + Error Erro @@ -605,22 +605,22 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Informação - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? A transação está acima do tamanho limite. Você ainda enviar ela com uma taxa de %1, que vai para os nós processam sua transação e ajuda a manter a rede. Você quer pagar a taxa? - + Up to date Atualizado - + Catching up... Recuperando o atraso ... - + Confirm transaction fee Confirmar taxa de transação @@ -669,7 +669,7 @@ Endereço: %4 Carteira está <b>criptografada</b> e atualmente <b>bloqueada</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Um erro fatal ocorreu. Bitcoin não pode continuar em segurança e irá fechar. @@ -677,7 +677,7 @@ Endereço: %4 ClientModel - + Network Alert Alerta da Rede @@ -1058,7 +1058,7 @@ Endereço: %4 Total de transações ainda não confirmadas, e que ainda não contam no saldo atual - + out of sync fora de sincronia @@ -1644,6 +1644,19 @@ Endereço: %4 Mensagem verificada. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2121,7 +2134,12 @@ Endereço: %4 WalletView - + + Export the data in the current tab to a file + Exportar os dados na aba atual para um arquivo + + + Backup Wallet Fazer cópia de segurança da Carteira diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 1ff4461cd..593c4e9d1 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -28,14 +28,14 @@ Distribuído sob uma licença de software MIT/X11, por favor verifique o ficheir Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no OpenSSL Toolkit (http://www.openssl.org/), software criptográfico escrito por Eric Young (eay@cryptsoft.com) e software UPnP escrito por Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Os programadores Bitcoin + The Bitcoin developers + @@ -66,7 +66,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open &Novo Endereço - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Estes são os seus endereços Bitcoin para receber pagamentos. Poderá enviar um endereço diferente para cada remetente para poder identificar os pagamentos. @@ -96,7 +96,17 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Apagar o endereço selecionado da lista - + + Export the data in the current tab to a file + Exportar os dados no separador actual para um ficheiro + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Verifique a mensagem para assegurar que foi assinada com o endereço Bitcoin especificado @@ -313,17 +323,17 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open BitcoinGUI - + Sign &message... Assinar &mensagem... - + Synchronizing with network... Sincronizando com a rede... - + &Overview Visã&o geral @@ -398,7 +408,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Mudar &Palavra-passe... - + Importing blocks from disk... Importando blocos do disco... @@ -408,12 +418,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Reindexando blocos no disco... - - &Export... - &Exportar... - - - + Send coins to a Bitcoin address Enviar moedas para um endereço bitcoin @@ -423,12 +428,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Modificar opções de configuração para bitcoin - - Export the data in the current tab to a file - Exportar os dados no separador actual para um ficheiro - - - + Backup wallet to another location Faça uma cópia de segurança da carteira para outra localização @@ -438,7 +438,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Mudar a frase de segurança utilizada na encriptação da carteira - + &Debug window Janela de &depuração @@ -448,23 +448,23 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Abrir consola de diagnóstico e depuração - + &Verify message... &Verificar mensagem... - - + + Bitcoin Bitcoin - + Wallet Carteira - + &Send &Enviar @@ -509,12 +509,12 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Verifique mensagens para assegurar que foram assinadas com o endereço Bitcoin especificado - + &File &Ficheiro - + &Settings Con&figurações @@ -529,12 +529,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Barra de separadores - - Actions toolbar - Barra de ações - - - + [testnet] [rede de testes] @@ -550,7 +545,12 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open %n ligação ativa à rede Bitcoin%n ligações ativas à rede Bitcoin - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. Processados %1 dos %2 blocos (estimados) do histórico de transacções. @@ -575,7 +575,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open %n semana%n semanas - + %1 behind %1 em atraso @@ -590,7 +590,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Transações posteriores poderão não ser imediatamente visíveis. - + Error Erro @@ -605,22 +605,22 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Informação - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Esta transação tem um tamanho superior ao limite máximo. Poderá enviá-la pagando uma taxa de %1, que será entregue ao nó que processar a sua transação e ajudará a suportar a rede. Deseja pagar a taxa? - + Up to date Atualizado - + Catching up... Recuperando... - + Confirm transaction fee Confirme a taxa de transação @@ -670,7 +670,7 @@ Endereço: %4 A carteira está <b>encriptada</b> e atualmente <b>bloqueada</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ocorreu um erro fatal. O Bitcoin não pode continuar com segurança e irá fechar. @@ -678,7 +678,7 @@ Endereço: %4 ClientModel - + Network Alert Alerta da Rede @@ -1059,7 +1059,7 @@ Endereço: %4 Total de transações ainda não confirmadas, e que não estão contabilizadas ainda no seu saldo actual - + out of sync fora de sincronia @@ -1645,6 +1645,19 @@ Endereço: %4 Mensagem verificada. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [rede de testes] + + TransactionDesc @@ -2122,7 +2135,12 @@ Endereço: %4 WalletView - + + Export the data in the current tab to a file + Exportar os dados no separador actual para um ficheiro + + + Backup Wallet Cópia de Segurança da Carteira diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index b5c92b82e..047cd48fe 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Adresă nouă - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Acestea sunt adresele dumneavoastră Bitcoin pentru a primi plăţi. Dacă doriţi, puteți da o adresa diferită fiecărui expeditor, pentru a putea ţine evidenţa plăţilor. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O Sterge adresele curent selectate din lista - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Verifica mesajul pentru a te asigura ca a fost insemnat cu o adresa bitcoin specifica @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Semneaza &mesaj... - + Synchronizing with network... Se sincronizează cu reţeaua... - + &Overview &Detalii @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Schimbă parola... - + Importing blocks from disk... Importare blocks de pe disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Exportă... - - - + Send coins to a Bitcoin address &Trimiteţi Bitcoin către o anumită adresă @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O Modifică setările pentru Bitcoin - - Export the data in the current tab to a file - Exporta datele din tab-ul curent catre un fiesier - - - + Backup wallet to another location Creaza copie de rezerva a portofelului intr-o locatie diferita @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Schimbă parola folosită pentru criptarea portofelului electronic - + &Debug window & Fereastra debug @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O Deschide consola de debug si diagnosticare - + &Verify message... Verifica mesajul - - + + Bitcoin Bitcoin - + Wallet Portofelul - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Fişier - + &Settings &Setări @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bara de ferestre de lucru - - Actions toolbar - Bara de acţiuni - - - + [testnet] [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n active connections to Bitcoin network%n active connections to Bitcoin network%n active connections to Bitcoin network - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Actualizat - + Catching up... Se actualizează... - + Confirm transaction fee Confirma taxa tranzactiei @@ -661,7 +661,7 @@ Address: %4 Portofelul electronic este <b>criptat</b> iar in momentul de faţă este <b>blocat</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert Alerta retea @@ -1050,7 +1050,7 @@ Address: %4 Totalul tranzacţiilor care aşteaptă să fie confirmate şi care nu sunt încă luate în calcul la afişarea soldului contului. - + out of sync Nu este sincronizat @@ -1636,6 +1636,19 @@ Address: %4 Mesaj verificat + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index c7bcd641f..192f98bc1 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -28,14 +28,14 @@ This product includes software developed by the OpenSSL Project for use in the O Этот продукт включает ПО, разработанное OpenSSL Project для использования в OpenSSL Toolkit (http://www.openssl.org/) и криптографическое ПО, написанное Eric Young (eay@cryptsoft.com) и ПО для работы с UPnP, написанное Thomas Bernard. - + Copyright Все права защищены - 2009-%1 The Bitcoin developers - 2009-%1 разработчики Bitcoin + The Bitcoin developers + Разработчики Bitcoin @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Новый адрес - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Это Ваши адреса для получения платежей. Вы можете дать разные адреса отправителям, чтобы отслеживать, кто именно вам платит. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O Удалить выбранный адрес из списка - + + Export the data in the current tab to a file + Экспортировать данные из вкладки в файл + + + + &Export + &Экспорт + + + Verify a message to ensure it was signed with a specified Bitcoin address Проверить сообщение, чтобы убедиться, что оно было подписано указанным адресом Bitcoin @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Подписать сообщение... - + Synchronizing with network... Синхронизация с сетью... - + &Overview О&бзор @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Изменить пароль... - + Importing blocks from disk... Импортируются блоки с диска... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Идёт переиндексация блоков на диске... - - &Export... - &Экспорт... - - - + Send coins to a Bitcoin address Отправить монеты на указанный адрес Bitcoin @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O Изменить параметры конфигурации Bitcoin - - Export the data in the current tab to a file - Экспортировать данные из вкладки в файл - - - + Backup wallet to another location Сделать резервную копию бумажника в другом месте @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O Изменить пароль шифрования бумажника - + &Debug window &Окно отладки @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O Открыть консоль отладки и диагностики - + &Verify message... &Проверить сообщение... - - + + Bitcoin Биткоин - + Wallet Бумажник - + &Send &Отправить @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O Проверить сообщения, чтобы удостовериться, что они были подписаны определённым адресом Bitcoin - + &File &Файл - + &Settings &Настройки @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O Панель вкладок - - Actions toolbar - Панель действий - - - + [testnet] [тестовая сеть] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n активное соединение с сетью%n активных соединений с сетью%n активных соединений с сетью - + + No block source available... + Источник блоков недоступен... + + + Processed %1 of %2 (estimated) blocks of transaction history. Обработано %1 из %2 (примерно) блоков истории транзакций. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n неделя%n недели%n недель - + %1 behind %1 позади @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O Транзакции после этой пока не будут видны. - + Error Ошибка @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O Информация - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Транзакция превышает максимальный размер. Вы можете провести её, заплатив комиссию %1, которая достанется узлам, обрабатывающим эту транзакцию, и поможет работе сети. Вы действительно хотите заплатить комиссию? - + Up to date Синхронизировано - + Catching up... Синхронизируется... - + Confirm transaction fee Подтвердите комиссию @@ -670,7 +670,7 @@ Address: %4 Бумажник <b>зашифрован</b> и в настоящее время <b>заблокирован</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Произошла неисправимая ошибка. Bitcoin не может безопасно продолжать работу и будет закрыт. @@ -678,7 +678,7 @@ Address: %4 ClientModel - + Network Alert Сетевая Тревога @@ -1059,7 +1059,7 @@ Address: %4 Общая сумма всех транзакций, которые до сих пор не подтверждены, и до сих пор не учитываются в текущем балансе - + out of sync не синхронизировано @@ -1645,6 +1645,19 @@ Address: %4 Сообщение проверено. + + SplashScreen + + + The Bitcoin developers + Разработчики Bitcoin + + + + [testnet] + [тестовая сеть] + + TransactionDesc @@ -2122,7 +2135,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + Экспортировать данные из вкладки в файл + + + Backup Wallet Сделать резервную копию бумажника diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index 9f0ba22a8..5449ece98 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Nová adresa - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Toto sú Vaše Bitcoin adresy pre prijímanie platieb. Môžete dať každému odosielateľovi inú rôznu adresu a tak udržiavať prehľad o platbách. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + Exportovať tento náhľad do súboru + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Podpísať &správu... - + Synchronizing with network... Synchronizácia so sieťou... - + &Overview &Prehľad @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Zmena Hesla... - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Export... - - - + Send coins to a Bitcoin address Poslať bitcoins na adresu @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O Upraviť možnosti nastavenia pre bitcoin - - Export the data in the current tab to a file - Exportovať tento náhľad do súboru - - - + Backup wallet to another location Zálohovať peňaženku na iné miesto @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Zmeniť heslo použité na šifrovanie peňaženky - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet Peňaženka - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Súbor - + &Settings &Nastavenia @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Lišta záložiek - - Actions toolbar - Lišta aktvivít - - - + [testnet] [testovacia sieť] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n aktívne spojenie v Bitcoin sieti%n aktívne spojenia v Bitcoin sieti%n aktívnych spojení v Bitconi sieti - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Aktualizovaný - + Catching up... Sťahujem... - + Confirm transaction fee @@ -664,7 +664,7 @@ Adresa: %4 Peňaženka je <b>zašifrovaná</b> a momentálne <b>zamknutá</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -672,7 +672,7 @@ Adresa: %4 ClientModel - + Network Alert @@ -1053,7 +1053,7 @@ Adresa: %4 Suma transakcií ktoré ešte neboli potvrdené a nezapočítavaju sa do celkového zostatku. - + out of sync @@ -1639,6 +1639,19 @@ Adresa: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testovacia sieť] + + TransactionDesc @@ -2116,7 +2129,12 @@ Adresa: %4 WalletView - + + Export the data in the current tab to a file + Exportovať tento náhľad do súboru + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 01802e996..17de8d72c 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Нова адреса - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Ово су Ваше Bitcoin адресе за примање уплата. Можете да сваком пошиљаоцу дате другачију адресу да би пратили ко је вршио уплате. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... Синхронизација са мрежом у току... - + &Overview &Општи преглед @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O Промени &лозинку... - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Извоз... - - - + Send coins to a Bitcoin address Пошаљите новац на bitcoin адресу @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O Изаберите могућности bitcoin-а - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O Мењање лозинке којом се шифрује новчаник - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet новчаник - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File &Фајл - + &Settings &Подешавања @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O Трака са картицама - - Actions toolbar - Трака са алаткама - - - + [testnet] [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n активна веза са Bitcoin мрежом%n активне везе са Bitcoin мрежом%n активних веза са Bitcoin мрежом - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Ажурно - + Catching up... Ажурирање у току... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 Новчаник јс <b>шифрован</b> и тренутно <b>закључан</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [testnet] + + TransactionDesc @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index a6a27ffba..119f7b6ef 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -29,14 +29,14 @@ Distribuerad under mjukvarulicensen MIT/X11, se den medföljande filen COPYING e Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användning i OpenSSL Toolkit (http://www.openssl.org/) och kryptografisk mjukvara utvecklad av Eric Young (eay@cryptsoft.com) samt UPnP-mjukvara skriven av Thomas Bernard. - + Copyright Copyright - 2009-%1 The Bitcoin developers - 2009-%1 Bitcoin-utvecklarna + The Bitcoin developers + Bitcoin-utvecklarna @@ -67,7 +67,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni &Ny adress - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Detta är dina Bitcoin-adresser för att ta emot betalningar. Du kan ge varje avsändare en egen adress så att du kan hålla reda på vem som betalar dig. @@ -97,7 +97,17 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Ta bort den valda adressen från listan - + + Export the data in the current tab to a file + Exportera informationen i den nuvarande fliken till en fil + + + + &Export + &Exportera + + + Verify a message to ensure it was signed with a specified Bitcoin address Verifiera meddelandet för att vara säker på att den var signerad med den specificerade Bitcoin-adressen @@ -314,17 +324,17 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni BitcoinGUI - + Sign &message... Signera &meddelande... - + Synchronizing with network... Synkroniserar med nätverk... - + &Overview &Översikt @@ -399,7 +409,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni &Byt Lösenord... - + Importing blocks from disk... Importerar block från disk... @@ -409,12 +419,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Återindexerar block på disken... - - &Export... - &Exportera... - - - + Send coins to a Bitcoin address Skicka mynt till en Bitcoin-adress @@ -424,12 +429,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Ändra konfigurationsalternativ för Bitcoin - - Export the data in the current tab to a file - Exportera informationen i den nuvarande fliken till en fil - - - + Backup wallet to another location Säkerhetskopiera plånboken till en annan plats @@ -439,7 +439,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Byt lösenord för kryptering av plånbok - + &Debug window &Debug fönster @@ -449,23 +449,23 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Öppna debug- och diagnostikkonsolen - + &Verify message... &Verifiera meddelande... - - + + Bitcoin Bitcoin - + Wallet Plånbok - + &Send &Skicka @@ -510,12 +510,12 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Verifiera meddelanden för att vara säker på att de var signerade med den specificerade Bitcoin-adressen - + &File &Arkiv - + &Settings &Inställningar @@ -530,12 +530,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Verktygsfält för Tabbar - - Actions toolbar - Verktygsfältet för Handlingar - - - + [testnet] [testnet] @@ -551,7 +546,12 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni %n aktiv anslutning till Bitcoin-nätverket%n aktiva anslutningar till Bitcoin-nätverket - + + No block source available... + Ingen block-källa tillgänglig... + + + Processed %1 of %2 (estimated) blocks of transaction history. Bearbetat %1 av %2 (uppskattade) block av transaktionshistorik. @@ -576,7 +576,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni %n vecka%n veckor - + %1 behind %1 efter @@ -591,7 +591,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Transaktioner efter denna kommer inte ännu vara synliga. - + Error Fel @@ -606,22 +606,22 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Information - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Transaktionen överskrider storleksgränsen. Du kan dock fortfarande skicka den mot en kostnad av %1, som går till noderna som behandlar din transaktion och bidrar till nätverket. Vill du betala denna avgift? - + Up to date Uppdaterad - + Catching up... Hämtar senaste... - + Confirm transaction fee Bekräfta överföringsavgift @@ -671,7 +671,7 @@ Adress: %4 Denna plånbok är <b>krypterad</b> och för närvarande <b>låst</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ett allvarligt fel har uppstått. Bitcoin kan inte längre köras säkert och kommer att avslutas. @@ -679,7 +679,7 @@ Adress: %4 ClientModel - + Network Alert Nätverkslarm @@ -1060,7 +1060,7 @@ Adress: %4 Totalt antal transaktioner som ännu inte bekräftats, och som ännu inte räknas med i aktuellt saldo - + out of sync osynkroniserad @@ -1646,6 +1646,19 @@ Adress: %4 Meddelandet är verifierad. + + SplashScreen + + + The Bitcoin developers + Bitcoin-utvecklarna + + + + [testnet] + [testnet] + + TransactionDesc @@ -2123,7 +2136,12 @@ Adress: %4 WalletView - + + Export the data in the current tab to a file + Exportera informationen i den nuvarande fliken till en fil + + + Backup Wallet Säkerhetskopiera Plånbok diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index fca6c0197..0557e4700 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -5,12 +5,12 @@ About Bitcoin - + เกี่ยวกับ บิตคอย์น <b>Bitcoin</b> version - + <b>บิตคอย์น<b>รุ่น @@ -23,13 +23,13 @@ This product includes software developed by the OpenSSL Project for use in the O - + Copyright - 2009-%1 The Bitcoin developers + The Bitcoin developers @@ -38,22 +38,22 @@ This product includes software developed by the OpenSSL Project for use in the O Address Book - + สมุดรายชื่อ Double-click to edit address or label - + ดับเบิลคลิก เพื่อแก้ไขที่อยู่ หรือชื่อ Create a new address - + สร้างที่อยู่ใหม่ Copy the currently selected address to the system clipboard - + คัดลอกที่อยู่ที่ถูกเลือกไปยัง คลิปบอร์ดของระบบ @@ -61,7 +61,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. @@ -91,7 +91,17 @@ This product includes software developed by the OpenSSL Project for use in the O - + + Export the data in the current tab to a file + + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address @@ -103,7 +113,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Delete - + ลบ @@ -128,7 +138,7 @@ This product includes software developed by the OpenSSL Project for use in the O Export Address Book Data - + ส่งออกรายชื่อทั้งหมด @@ -138,12 +148,12 @@ This product includes software developed by the OpenSSL Project for use in the O Error exporting - + ส่งออกผิดพลาด Could not write to file %1. - + ไม่สามารถเขียนไปยังไฟล์ %1 @@ -151,17 +161,17 @@ This product includes software developed by the OpenSSL Project for use in the O Label - + ชื่อ Address - + ที่อยู่ (no label) - + (ไม่มีชื่อ) @@ -174,17 +184,17 @@ This product includes software developed by the OpenSSL Project for use in the O Enter passphrase - + ใส่รหัสผ่าน New passphrase - + รหัสผา่นใหม่ Repeat new passphrase - + กรุณากรอกรหัสผ่านใหม่อีกครั้งหนึ่ง @@ -194,7 +204,7 @@ This product includes software developed by the OpenSSL Project for use in the O Encrypt wallet - + กระเป๋าสตางค์ที่เข้ารหัส @@ -204,7 +214,7 @@ This product includes software developed by the OpenSSL Project for use in the O Unlock wallet - + เปิดกระเป๋าสตางค์ @@ -214,22 +224,22 @@ This product includes software developed by the OpenSSL Project for use in the O Decrypt wallet - + ถอดรหัสกระเป๋าสตางค์ Change passphrase - + เปลี่ยนรหัสผ่าน Enter the old and new passphrase to the wallet. - + กรอกรหัสผ่านเก่าและรหัสผ่านใหม่สำหรับกระเป๋าสตางค์ Confirm wallet encryption - + ยืนยันการเข้ารหัสกระเป๋าสตางค์ @@ -256,7 +266,7 @@ This product includes software developed by the OpenSSL Project for use in the O Wallet encrypted - + กระเป๋าสตางค์ถูกเข้ารหัสเรียบร้อยแล้ว @@ -269,7 +279,7 @@ This product includes software developed by the OpenSSL Project for use in the O Wallet encryption failed - + การเข้ารหัสกระเป๋าสตางค์ผิดพลาด @@ -280,7 +290,7 @@ This product includes software developed by the OpenSSL Project for use in the O The supplied passphrases do not match. - + รหัสผ่านที่คุณกรอกไม่ตรงกัน @@ -308,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -393,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -403,12 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - - - - + Send coins to a Bitcoin address @@ -418,12 +423,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Export the data in the current tab to a file - - - - + Backup wallet to another location @@ -433,7 +433,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Debug window @@ -443,23 +443,23 @@ This product includes software developed by the OpenSSL Project for use in the O - + &Verify message... - - + + Bitcoin - + Wallet - + &Send @@ -504,12 +504,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + &File - + &Settings @@ -524,12 +524,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - Actions toolbar - - - - + [testnet] @@ -545,7 +540,12 @@ This product includes software developed by the OpenSSL Project for use in the O - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -570,7 +570,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -585,7 +585,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error @@ -600,22 +600,22 @@ This product includes software developed by the OpenSSL Project for use in the O - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date - + Catching up... - + Confirm transaction fee @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -669,7 +669,7 @@ Address: %4 ClientModel - + Network Alert @@ -1050,7 +1050,7 @@ Address: %4 - + out of sync @@ -1636,6 +1636,19 @@ Address: %4 + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + TransactionDesc @@ -1838,7 +1851,7 @@ Address: %4 Address - + ที่อยู่ @@ -2072,12 +2085,12 @@ Address: %4 Label - + ชื่อ Address - + ที่อยู่ @@ -2092,12 +2105,12 @@ Address: %4 Error exporting - + ส่งออกผิดพลาด Could not write to file %1. - + ไม่สามารถเขียนไปยังไฟล์ %1 @@ -2113,7 +2126,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index 02760f4b4..0563ca7c8 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -28,14 +28,14 @@ This product includes software developed by the OpenSSL Project for use in the O Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl.org/) için geliştirilen yazılımlar, Eric Young (eay@cryptsoft.com) tarafından hazırlanmış şifreleme yazılımları ve Thomas Bernard tarafından programlanmış UPnP yazılımı içerir. - + Copyright Telif hakkı - 2009-%1 The Bitcoin developers - 2009-%1 Bitcoin geliştiricileri + The Bitcoin developers + Bitcoin geliştiricileri @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Yeni adres - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Bunlar, ödeme almak için Bitcoin adresleridir. Kimin ödeme yaptığını izleyebilmek için her ödeme yollaması gereken kişiye değişik bir adres verebilirsiniz. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O Seçili adresi listeden sil - + + Export the data in the current tab to a file + Güncel sekmedeki verileri bir dosyaya aktar + + + + &Export + &Dışa aktar + + + Verify a message to ensure it was signed with a specified Bitcoin address Belirtilen Bitcoin adresi ile imzalandığını doğrulamak için bir mesajı kontrol et @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Mesaj imzala... - + Synchronizing with network... Şebeke ile senkronizasyon... - + &Overview &Genel bakış @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O Parolayı &değiştir... - + Importing blocks from disk... Bloklar diskten içe aktarılıyor... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Diskteki bloklar yeniden endeksleniyor... - - &Export... - &Dışa aktar... - - - + Send coins to a Bitcoin address Bir Bitcoin adresine Bitcoin yolla @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin seçeneklerinin yapılandırmasını değiştir - - Export the data in the current tab to a file - Güncel sekmedeki verileri bir dosyaya aktar - - - + Backup wallet to another location Cüzdanı diğer bir konumda yedekle @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O Cüzdan şifrelemesi için kullanılan parolayı değiştir - + &Debug window &Hata ayıklama penceresi @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O Hata ayıklama ve teşhis penceresini aç - + &Verify message... Mesaj &kontrol et... - - + + Bitcoin Bitcoin - + Wallet Cüzdan - + &Send &Gönder @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O Belirtilen Bitcoin adresleri ile imzalandıklarından emin olmak için mesajları kontrol et - + &File &Dosya - + &Settings &Ayarlar @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O Sekme araç çubuğu - - Actions toolbar - Faaliyet araç çubuğu - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin şebekesine %n faal bağlantıBitcoin şebekesine %n faal bağlantı - + + No block source available... + Hiçbir blok kaynağı mevcut değil... + + + Processed %1 of %2 (estimated) blocks of transaction history. Muamele tarihçesinin toplam (tahmini) %2 blokundan %1 blok işlendi. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n hafta%n hafta - + %1 behind %1 geride @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bundan sonraki muameleler henüz görüntülenemez. - + Error Hata @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O Bilgi - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? Bu muamele boyut sınırlarını aşmıştır. Gene de %1 ücret ödeyerek gönderebilirsiniz, ki bu ücret muamelenizi işleyen ve şebekeye yardım eden düğümlere ödenecektir. Ücreti ödemek istiyor musunuz? - + Up to date Güncel - + Catching up... Aralık kapatılıyor... - + Confirm transaction fee Muamele ücretini teyit et @@ -670,7 +670,7 @@ Adres: %4 Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilitlidir</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ciddi bir hata oluştu. Bitcoin artık güvenli bir şekilde işlemeye devam edemez ve kapanacaktır. @@ -678,7 +678,7 @@ Adres: %4 ClientModel - + Network Alert Şebeke hakkında uyarı @@ -1059,7 +1059,7 @@ Adres: %4 Doğrulanması beklenen ve henüz güncel bakiyeye ilâve edilmemiş muamelelerin toplamı - + out of sync eşleşme dışı @@ -1645,6 +1645,19 @@ Adres: %4 Mesaj doğrulandı. + + SplashScreen + + + The Bitcoin developers + Bitcoin geliştiricileri + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Adres: %4 WalletView - + + Export the data in the current tab to a file + Güncel sekmedeki verileri bir dosyaya aktar + + + Backup Wallet Cüzdanı yedekle diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 1d7c2980f..c59c2a2f8 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -28,14 +28,14 @@ This product includes software developed by the OpenSSL Project for use in the O Цей продукт включає в себе програмне забезпечення, розроблене в рамках проекту OpenSSL (http://www.openssl.org/), криптографічне програмне забезпечення, написане Еріком Янгом (eay@cryptsoft.com), та функції для роботи з UPnP, написані Томасом Бернардом. - + Copyright Авторське право - 2009-%1 The Bitcoin developers - 2009-%1 Розробники Bitcoin + The Bitcoin developers + @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Створити адресу - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. Це ваші адреси для отримання платежів. Ви можете давати різні адреси різним людям, таким чином маючи можливість відслідкувати хто конкретно і скільки вам заплатив. @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O Вилучити вибрані адреси з переліку - + + Export the data in the current tab to a file + Експортувати дані з поточної вкладки в файл + + + + &Export + + + + Verify a message to ensure it was signed with a specified Bitcoin address Перевірте повідомлення для впевненості, що воно підписано вказаною Bitcoin-адресою @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Підписати повідомлення... - + Synchronizing with network... Синхронізація з мережею... - + &Overview &Огляд @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O Змінити парол&ь... - + Importing blocks from disk... Імпорт блоків з диску... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O - - &Export... - &Експорт... - - - + Send coins to a Bitcoin address Відправити монети на вказану адресу @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O Редагувати параметри - - Export the data in the current tab to a file - Експортувати дані з поточної вкладки в файл - - - + Backup wallet to another location Резервне копіювання гаманця в інше місце @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O Змінити пароль, який використовується для шифрування гаманця - + &Debug window Вікно зневадження @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O Відкрити консоль зневадження і діагностики - + &Verify message... Перевірити повідомлення... - - + + Bitcoin Bitcoin - + Wallet Гаманець - + &Send @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O Перевірте повідомлення для впевненості, що воно підписано вказаною Bitcoin-адресою - + &File &Файл - + &Settings &Налаштування @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O Панель вкладок - - Actions toolbar - Панель дій - - - + [testnet] [тестова мережа] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O %n активне з'єднання з мережею%n активні з'єднання з мережею%n активних з'єднань з мережею - + + No block source available... + + + + Processed %1 of %2 (estimated) blocks of transaction history. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %1 behind @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Error Помилка @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O Інформація - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Up to date Синхронізовано - + Catching up... Синхронізується... - + Confirm transaction fee Підтвердити комісію @@ -670,7 +670,7 @@ Address: %4 <b>Зашифрований</b> гаманець <b>заблоковано</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -678,7 +678,7 @@ Address: %4 ClientModel - + Network Alert Сповіщення мережі @@ -1059,7 +1059,7 @@ Address: %4 Загальна сума всіх транзакцій, які ще не підтверджені, та до цих пір не враховуються в загальному балансі - + out of sync не синхронізовано @@ -1645,6 +1645,19 @@ Address: %4 Повідомлення перевірено. + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + [тестова мережа] + + TransactionDesc @@ -2122,7 +2135,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + Експортувати дані з поточної вкладки в файл + + + Backup Wallet diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index e8d84f40f..3b5067e38 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -28,14 +28,14 @@ Distributed under the MIT/X11 software license, see the accompanying file COPYIN This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - + Copyright 版权 - 2009-%1 The Bitcoin developers - 2009-%1 The Bitcoin developers + The Bitcoin developers + Bitcoin-qt 客户端开发团队 @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O &新建地址 - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. 这是您用来收款的比特币地址。为了标记不同的资金来源,建议为每个付款人保留不同的收款地址。 @@ -96,7 +96,17 @@ This product includes software developed by the OpenSSL Project for use in the O 从列表中删除选中的地址 - + + Export the data in the current tab to a file + 导出当前数据到文件 + + + + &Export + &导出 + + + Verify a message to ensure it was signed with a specified Bitcoin address 验证消息,确保消息是由指定的比特币地址签名过的。 @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... 对&消息签名... - + Synchronizing with network... 正在与网络同步... - + &Overview &概况 @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &修改密码... - + Importing blocks from disk... 正在从磁盘导入数据块... @@ -408,12 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O 正在为数据块建立索引... - - &Export... - &导出... - - - + Send coins to a Bitcoin address 向一个比特币地址发送比特币 @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O 设置选项 - - Export the data in the current tab to a file - 导出当前数据到文件 - - - + Backup wallet to another location 备份钱包到其它文件夹 @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O 修改钱包加密口令 - + &Debug window &调试窗口 @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O 在诊断控制台调试 - + &Verify message... &验证消息... - - + + Bitcoin 比特币 - + Wallet 钱包 - + &Send &发送 @@ -509,12 +509,12 @@ This product includes software developed by the OpenSSL Project for use in the O 校验消息,确保该消息是由指定的比特币地址所有者签名的 - + &File &文件 - + &Settings &设置 @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O 分页工具栏 - - Actions toolbar - 动作工具栏 - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O 到比特币网络的连接共有%n条 - + + No block source available... + No block source available... + + + Processed %1 of %2 (estimated) blocks of transaction history. %1 / %2 个交易历史的区块已下载 @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n 周前 - + %1 behind 落后 %1 @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O 在此之后的交易尚未可见 - + Error 错误 @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O 信息 - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? 该交易的字节数超标。您可以选择支付%1的交易费给处理您的交易的网络节点,有助于比特币网络的运行。您愿意支付这笔交易费用吗? - + Up to date 最新状态 - + Catching up... 更新中... - + Confirm transaction fee 确认交易费 @@ -670,7 +670,7 @@ Address: %4 钱包已被<b>加密</b>,当前为<b>锁定</b>状态 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. 发生严重错误。 @@ -678,7 +678,7 @@ Address: %4 ClientModel - + Network Alert 网络警报 @@ -1060,7 +1060,7 @@ Address: %4 尚未确认的交易总额, 未计入当前余额 - + out of sync 数据同步中 @@ -1646,6 +1646,19 @@ Address: %4 消息验证成功。 + + SplashScreen + + + The Bitcoin developers + Bitcoin-qt 客户端开发团队 + + + + [testnet] + [testnet] + + TransactionDesc @@ -2123,7 +2136,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + 导出当前数据到文件 + + + Backup Wallet 备份钱包 diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index bf3375164..7ccd5462d 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -28,14 +28,14 @@ This product includes software developed by the OpenSSL Project for use in the O 此產品也包含了由 OpenSSL Project 所開發的 OpenSSL Toolkit (http://www.openssl.org/) 軟體, 由 Eric Young (eay@cryptsoft.com) 撰寫的加解密軟體, 以及由 Thomas Bernard 所撰寫的 UPnP 軟體. - + Copyright 版權 - 2009-%1 The Bitcoin developers - Bitcoin 開發人員自西元 2009 至 %1 年起所有 + The Bitcoin developers + 位元幣開發人員 @@ -66,7 +66,7 @@ This product includes software developed by the OpenSSL Project for use in the O 新增位址 - + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. 這些是你用來收款的位元幣位址. 你可以提供不同的位址給不同的付款人, 來追蹤是誰支付給你. @@ -83,7 +83,7 @@ This product includes software developed by the OpenSSL Project for use in the O Sign a message to prove you own a Bitcoin address - 簽署一則訊息來證明一個位元幣位址是你的 + 簽署訊息是用來證明位元幣位址是你的 @@ -96,9 +96,19 @@ This product includes software developed by the OpenSSL Project for use in the O 從列表中刪除目前選取的位址 - + + Export the data in the current tab to a file + 將目前分頁的資料匯出存成檔案 + + + + &Export + 匯出 + + + Verify a message to ensure it was signed with a specified Bitcoin address - 驗證一則訊息以確認它是用指定的位元幣位址簽署的 + 驗證訊息是用來確認訊息是用指定的位元幣位址簽署的 @@ -113,7 +123,7 @@ This product includes software developed by the OpenSSL Project for use in the O These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - + 這是你用來付款的位元幣位址. 在付錢之前, 務必要檢查金額和收款位址是否正確. @@ -313,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... 訊息簽署... - + Synchronizing with network... 網路同步中... - + &Overview 總覽 @@ -398,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O 密碼變更... - + Importing blocks from disk... 從磁碟匯入區塊中... @@ -408,14 +418,9 @@ This product includes software developed by the OpenSSL Project for use in the O 重建磁碟區塊索引中... - - &Export... - 匯出... - - - + Send coins to a Bitcoin address - 付錢到一個位元幣位址 + 付錢到位元幣位址 @@ -423,12 +428,7 @@ This product includes software developed by the OpenSSL Project for use in the O 修改位元幣的設定選項 - - Export the data in the current tab to a file - 將目前分頁的資料匯出存成檔案 - - - + Backup wallet to another location 將錢包備份到其它地方 @@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O 變更錢包加密用的密碼 - + &Debug window 除錯視窗 @@ -448,23 +448,23 @@ This product includes software developed by the OpenSSL Project for use in the O 開啓除錯與診斷主控台 - + &Verify message... 驗證訊息... - - + + Bitcoin 位元幣 - + Wallet 錢包 - + &Send 付出 @@ -506,15 +506,15 @@ This product includes software developed by the OpenSSL Project for use in the O Verify messages to ensure they were signed with specified Bitcoin addresses - 驗證訊息以確認那是用指定的位元幣位址簽署的 + 驗證訊息來確認是用指定的位元幣位址簽署的 - + &File 檔案 - + &Settings 設定 @@ -529,12 +529,7 @@ This product includes software developed by the OpenSSL Project for use in the O 分頁工具列 - - Actions toolbar - 動作工具列 - - - + [testnet] [testnet] @@ -550,7 +545,12 @@ This product includes software developed by the OpenSSL Project for use in the O 與位元幣網路有 %n 個連線在使用中 - + + No block source available... + 目前沒有區塊來源... + + + Processed %1 of %2 (estimated) blocks of transaction history. 已處理了估計全部 %2 個中的 %1 個區塊的交易紀錄. @@ -575,7 +575,7 @@ This product includes software developed by the OpenSSL Project for use in the O %n 個星期 - + %1 behind 落後 %1 @@ -590,7 +590,7 @@ This product includes software developed by the OpenSSL Project for use in the O 會看不見在這之後的交易. - + Error 錯誤 @@ -605,22 +605,22 @@ This product includes software developed by the OpenSSL Project for use in the O 資訊 - + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? 這筆交易的資料大小超過限制了. 你還是可以付出 %1 的費用來傳送, 這筆費用會付給處理你的交易的節點, 並幫助維持整個網路. 你願意支付這項費用嗎? - + Up to date 最新狀態 - + Catching up... 進度追趕中... - + Confirm transaction fee 確認交易手續費 @@ -669,7 +669,7 @@ Address: %4 錢包<b>已加密</b>並且正<b>上鎖中</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. 發生了致命的錯誤. 位元幣程式無法再繼續安全執行, 只好結束. @@ -677,7 +677,7 @@ Address: %4 ClientModel - + Network Alert 網路警報 @@ -707,7 +707,7 @@ Address: %4 The address associated with this address book entry. This can only be modified for sending addresses. - 與這個位址簿項目關聯的位址. 只能修改付款位址. + 與這個位址簿項目關聯的位址. 付款位址才能被更改. @@ -717,7 +717,7 @@ Address: %4 New sending address - 新付款位址 + 新增付款位址 @@ -1059,7 +1059,7 @@ Address: %4 尚未確認之交易的總額, 不包含在目前餘額中 - + out of sync 沒同步 @@ -1375,7 +1375,7 @@ Address: %4 Duplicate address found, can only send to each address once per send operation. - 發現有重複的位址. 在一次付款動作中, 只能付給每個位址一次. + 發現有重複的位址. 每個付款動作中, 只能付給個別的位址一次. @@ -1514,7 +1514,7 @@ Address: %4 Sign the message to prove you own this Bitcoin address - 簽署一則訊息來證明一個位元幣位址是你的 + 簽署訊息是用來證明這個位元幣位址是你的 @@ -1550,7 +1550,7 @@ Address: %4 Verify the message to ensure it was signed with the specified Bitcoin address - 驗證這則訊息以確認它是用指定的位元幣位址簽署的 + 驗證訊息是用來確認訊息是用指定的位元幣位址簽署的 @@ -1645,6 +1645,19 @@ Address: %4 訊息已驗證. + + SplashScreen + + + The Bitcoin developers + 位元幣開發人員 + + + + [testnet] + [testnet] + + TransactionDesc @@ -2122,7 +2135,12 @@ Address: %4 WalletView - + + Export the data in the current tab to a file + 將目前分頁的資料匯出存成檔案 + + + Backup Wallet 錢包備份 @@ -2167,7 +2185,7 @@ Address: %4 Send command to -server or bitcoind - 送指令至 -server 或 bitcoind + 送指令給 -server 或 bitcoind @@ -2539,7 +2557,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Set the number of threads to service RPC calls (default: 4) - + 設定處理 RPC 服務請求的執行緒數目 (預設為 4) @@ -2619,7 +2637,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Send trace/debug info to console instead of debug.log file - 輸出追蹤或除錯資訊至終端機, 而非 debug.log 檔案 + 在終端機顯示追蹤或除錯資訊, 而非寫到 debug.log 檔 From da986f793d839d63692aa8b497f42c30fd584c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chuck=20LeDuc=20D=C3=ADaz?= Date: Sun, 5 May 2013 23:32:35 +0300 Subject: [PATCH 27/69] Update readme with better link syntax (for clickable links) and better readability. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a50736d4e..d675d73ad 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ Unit tests for the GUI code are in `src/qt/test/`. To compile and run them: Every pull request is built for both Windows and Linux on a dedicated server, and unit and sanity tests are automatically run. The binaries produced may be -used for manual QA testing -- a link to them will appear in a comment on the -pull request posted by 'BitcoinPullTester'. See `https://github.com/TheBlueMatt/test-scripts` +used for manual QA testing — a link to them will appear in a comment on the +pull request posted by [BitcoinPullTester](https://github.com/BitcoinPullTester). See https://github.com/TheBlueMatt/test-scripts for the build/test scripts. ### Manual Quality Assurance (QA) Testing @@ -79,4 +79,4 @@ for the build/test scripts. Large changes should have a test plan, and should be tested by somebody other than the developer who wrote the code. -See `https://github.com/bitcoin/QA/` for how to create a test plan. +See https://github.com/bitcoin/QA/ for how to create a test plan. From e7d41be8703cc577b6eedb85bd7bba018442e6e0 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Tue, 7 May 2013 09:14:23 +0200 Subject: [PATCH 28/69] translations update 2013-05-07 - updates bitcoin_en.ts and bitcoinstrings.cpp - integrates current translations from Transifex --- src/qt/bitcoinstrings.cpp | 7 +- src/qt/locale/bitcoin_ar.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_bg.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_bs.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_ca.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_ca_ES.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_cs.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_cy.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_da.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_de.ts | 155 +++++++++++------------ src/qt/locale/bitcoin_el_GR.ts | 223 ++++++++++++++++----------------- src/qt/locale/bitcoin_en.ts | 139 ++++++++++++-------- src/qt/locale/bitcoin_eo.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_es.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_es_CL.ts | 153 +++++++++++----------- src/qt/locale/bitcoin_et.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_eu_ES.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_fa.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_fa_IR.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_fi.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_fr.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_fr_CA.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_gu_IN.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_he.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_hi_IN.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_hr.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_hu.ts | 153 +++++++++++----------- src/qt/locale/bitcoin_it.ts | 153 +++++++++++----------- src/qt/locale/bitcoin_ja.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_la.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_lt.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_lv_LV.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_nb.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_nl.ts | 153 +++++++++++----------- src/qt/locale/bitcoin_pl.ts | 157 +++++++++++------------ src/qt/locale/bitcoin_pt_BR.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_pt_PT.ts | 163 ++++++++++++------------ src/qt/locale/bitcoin_ro_RO.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_ru.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_sk.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_sr.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_sv.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_th_TH.ts | 149 +++++++++++----------- src/qt/locale/bitcoin_tr.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_uk.ts | 151 +++++++++++----------- src/qt/locale/bitcoin_zh_CN.ts | 153 +++++++++++----------- src/qt/locale/bitcoin_zh_TW.ts | 153 +++++++++++----------- 47 files changed, 3411 insertions(+), 3610 deletions(-) diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 5481b5ce0..4dae8999c 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -113,7 +113,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires new QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: system error: "), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), @@ -138,6 +137,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Information"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -tor address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -minrelaytxfee=: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -mintxfee=: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"), QT_TRANSLATE_NOOP("bitcoin-core", "List commands"), @@ -175,6 +176,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: 250 QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: 4)"), QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: bitcoin.conf)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (default: 5000)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"), @@ -184,6 +186,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "System error: "), QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"), QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"), +QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"), +QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must be positive"), +QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 08045edde..8c7e3c57c 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 52c88822d..f0d1ff6b7 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Подписване на &съобщение... - + Synchronizing with network... Синхронизиране с мрежата... - + &Overview &Баланс @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Смяна на паролата... - + Importing blocks from disk... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address Изпращане към Биткоин адрес @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Проверка на съобщение... - - + + Bitcoin Биткоин - + Wallet Портфейл - + &Send @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network %n връзка към Биткоин мрежата%n връзки към Биткоин мрежата @@ -666,7 +666,7 @@ Address: %4 Портфейлът е <b>криптиран</b> и <b>заключен</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -805,8 +805,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Такса за транзакция на kB. Подпомага участниците в мрежата, които верифицират транзакции (miners). По-висока стойност би трябвало да ускори обработката на транзакции. Повечето транзакции са около 1 kB. Препоръчителна стойност - 0.0005 BTC. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2131,12 +2131,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Запишете данните от текущия раздел във файл - + Backup Wallet @@ -2169,12 +2174,12 @@ Address: %4 bitcoin-core - + Bitcoin version Биткоин версия - + Usage: @@ -2184,7 +2189,7 @@ Address: %4 - + List commands @@ -2194,7 +2199,7 @@ Address: %4 - + Options: Опции: @@ -2209,17 +2214,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2229,7 +2224,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2239,7 +2234,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2259,22 +2254,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2284,12 +2279,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2318,11 +2313,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2349,12 +2339,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2394,7 +2379,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2414,7 +2399,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2514,7 +2499,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2524,7 +2514,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2544,12 +2539,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2574,7 +2574,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2689,12 +2689,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2734,12 +2734,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2754,12 +2754,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Зареждане на адресите... @@ -2774,12 +2774,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2789,7 +2789,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Невалиден -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2809,7 +2809,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2829,7 +2829,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Зареждане на блок индекса... - + Add a node to connect to and attempt to keep the connection open @@ -2839,7 +2839,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2849,15 +2849,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Зареждане на портфейла... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2869,22 +2864,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Преразглеждане на последовтелността от блокове... - + Done loading Зареждането е завършено - + To use the %s option - + Error Грешка - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 4f6064d5a..3bddc0527 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 482005bdb..1cd781d5c 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 864cfeb37..a9d40f4a0 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Signar &missatge... - + Synchronizing with network... Sincronitzant amb la xarxa ... - + &Overview &Panorama general @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Canviar contrasenya... - + Importing blocks from disk... Important blocs del disc.. @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O Re-indexant blocs al disc... - + Send coins to a Bitcoin address Enviar monedes a una adreça Bitcoin @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Verifica el missatge.. - - + + Bitcoin Bitcoin - + Wallet Moneder - + &Send &Enviar @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O Client Bitcoin - + %n active connection(s) to Bitcoin network %n connexió activa a la xarxa Bitcoin%n connexions actives a la xarxa Bitcoin @@ -661,7 +661,7 @@ Address: %4 El moneder està <b>encriptat</b> i actualment <b>bloquejat</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ha tingut lloc un error fatal. Bitcoin no pot continuar executant-se de manera segura i es tancará. @@ -800,8 +800,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Commisió de transacció opcional per kB que ajuda a garantir que les teves transaccions son processades ràpidament. La majoría de transaccions són de 1kB. Commisió recomanada de 0,01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet Realitzar còpia de seguretat del moneder @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version Versió de Bitcoin - + Usage: Ús: @@ -2179,7 +2184,7 @@ Address: %4 Enviar comanda a -servidor o bitcoind - + List commands Llista d'ordres @@ -2189,7 +2194,7 @@ Address: %4 Obtenir ajuda per a un ordre. - + Options: Opcions: @@ -2204,17 +2209,7 @@ Address: %4 Especificar arxiu pid (per defecte: bitcoind.pid) - - Generate coins - Generar monedes - - - - Don't generate coins - No generar monedes - - - + Specify data directory Especificar directori de dades @@ -2224,7 +2219,7 @@ Address: %4 Establir tamany de la memoria cau en megabytes (per defecte: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Escoltar connexions a <port> (per defecte: 8333 o testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 Mantenir com a molt <n> connexions a peers (per defecte: 125) - + Connect to a node to retrieve peer addresses, and disconnect Connectar al node per obtenir les adreces de les connexions, i desconectar @@ -2254,22 +2249,22 @@ Address: %4 Nombre de segons abans de reconectar amb connexions errònies (per defecte: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Ha sorgit un error al configurar el port RPC %u escoltant a IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Escoltar connexions JSON-RPC al port <port> (per defecte: 8332 o testnet:18332) - + Accept command line and JSON-RPC commands Acceptar línia d'ordres i ordres JSON-RPC - + Run in the background as a daemon and accept commands Executar en segon pla com a programa dimoni i acceptar ordres @@ -2279,12 +2274,12 @@ Address: %4 Usar la xarxa de prova - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceptar connexions d'afora (per defecte: 1 si no -proxy o -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. No es pot bloquejar el directori de dades %s. Probablement Bitcoin ja estigui en execució. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Error inicialitzant l'entorn de la base de dades %s! Per recuperar, FES UNA COPIA DE SEGURETAT D'AQUEST DIRECTORI, aleshores elimina tot el contingut TRET DEL wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Establir una mida màxima de transaccions d'alta prioritat/baixa comisió en bytes (per defecte: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Establir el nombre d'execucions en paralel del script de verificació (1-16, 0=auto, per defecte: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Aquesta és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Opcions de la creació de blocs: - + Connect only to the specified node(s) Connectar només al(s) node(s) especificats @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Vols reconstruir la base de dades de blocs ara? - + Error initializing block database Error carregant la base de dades de blocs @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cerca punts de connexió usant rastreig de DNS (per defecte: 1 tret d'usar -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Quants blocs s'han de confirmar a l'inici (per defecte: 288, 0 = tots) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Com verificar el bloc (0-4, per defecte 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Reconstruir l'índex de la cadena de blocs dels arxius actuals blk000??.dat @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verificant moneder... - + Imports blocks from external blk000??.dat file Importa blocs de un fitxer blk000??.dat extern - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information &Informació @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Mida màxima del buffer d'enviament per a cada connexió, <n>*1000 bytes (default: 5000) - + Only accept block chain matching built-in checkpoints (default: 1) Tan sols acceptar cadenes de blocs que coincideixin amb els punts de prova (per defecte: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Contrasenya per a connexions JSON-RPC - + Allow JSON-RPC connections from specified IP address Permetre connexions JSON-RPC d'adreces IP específiques - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar ordre al node en execució a <ip> (per defecte: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Clau privada del servidor (per defecte: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Xifrats acceptats (per defecte: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Aquest misatge d'ajuda @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Connectar a través de socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Permetre consultes DNS per a -addnode, -seednode i -connect - + Loading addresses... Carregant adreces... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error carregant wallet.dat: El moneder requereix una versió de Bitcoin més moderna - + Wallet needed to be rewritten: restart Bitcoin to complete El moneder necesita ser re-escrit: re-inicia Bitcoin per a completar la tasca - + Error loading wallet.dat Error carregant wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Adreça -proxy invalida: '%s' - + Unknown network specified in -onlynet: '%s' Xarxa desconeguda especificada a -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es pot resoldre l'adreça -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantitat invalida per a -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Carregant índex de blocs... - + Add a node to connect to and attempt to keep the connection open Afegir un node per a connectar's-hi i intentar mantenir la connexió oberta @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossible d'unir %s en aquest ordinador. Probablement Bitcoin ja estigui en execució. - + Fee per KB to add to transactions you send Comisió a afegir per cada KB de transaccions que enviïs @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Carregant moneder... - + Cannot downgrade wallet No es pot reduir la versió del moneder - - - Cannot initialize keypool - No es pot inicialitzar el conjunt de claus - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Re-escanejant... - + Done loading Càrrega acabada - + To use the %s option Utilitza la opció %s - + Error Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 2c1e4caf2..03713fd02 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -323,17 +323,17 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open BitcoinGUI - + Sign &message... Po&depiš zprávu... - + Synchronizing with network... Synchronizuji se se sítí... - + &Overview &Přehled @@ -408,7 +408,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Změň &heslo... - + Importing blocks from disk... Importuji bloky z disku... @@ -418,7 +418,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Vytvářím nový index bloků na disku... - + Send coins to a Bitcoin address Pošli mince na Bitcoinovou adresu @@ -453,18 +453,18 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open &Ověř zprávu... - - + + Bitcoin Bitcoin - + Wallet Peněženka - + &Send &Pošli @@ -540,7 +540,7 @@ Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v Open Bitcoin klient - + %n active connection(s) to Bitcoin network %n aktivní spojení do Bitcoinové sítě%n aktivní spojení do Bitcoinové sítě%n aktivních spojení do Bitcoinové sítě @@ -670,7 +670,7 @@ Adresa: %4 Peněženka je <b>zašifrovaná</b> a momentálně <b>zamčená</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Stala se fatální chyba. Bitcoin nemůže bezpečně pokračovat v činnosti, a proto skončí. @@ -809,8 +809,8 @@ Adresa: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Dobrovolný transakční poplatek za každý započatý kB dopomáhá k rychlému zpracování tvých transakcí. Většina transakcí má do 1 kB. Doporučená výše poplatku je 0.01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Dobrovolný transakční poplatek za každý započatý kB dopomáhá k rychlému zpracování tvých transakcí. Většina transakcí má do 1 kB. @@ -2135,12 +2135,17 @@ Adresa: %4 WalletView - + + &Export + &Export + + + Export the data in the current tab to a file Exportuj data z tohoto panelu do souboru - + Backup Wallet Záloha peněženky @@ -2173,12 +2178,12 @@ Adresa: %4 bitcoin-core - + Bitcoin version Verze Bitcoinu - + Usage: Užití: @@ -2188,7 +2193,7 @@ Adresa: %4 Poslat příkaz pro -server nebo bitcoind - + List commands Výpis příkazů @@ -2198,7 +2203,7 @@ Adresa: %4 Získat nápovědu pro příkaz - + Options: Možnosti: @@ -2213,17 +2218,7 @@ Adresa: %4 PID soubor (výchozí: bitcoind.pid) - - Generate coins - Generovat mince - - - - Don't generate coins - Negenerovat mince - - - + Specify data directory Adresář pro data @@ -2233,7 +2228,7 @@ Adresa: %4 Nastavit velikost databázové vyrovnávací paměti v megabajtech (výchozí: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Čekat na spojení na <portu> (výchozí: 8333 nebo testnet: 18333) @@ -2243,7 +2238,7 @@ Adresa: %4 Povolit nejvýše <n> připojení k uzlům (výchozí: 125) - + Connect to a node to retrieve peer addresses, and disconnect Připojit se k uzlu, získat adresy jeho protějšků a odpojit se @@ -2263,22 +2258,22 @@ Adresa: %4 Doba ve vteřinách, po kterou se nebudou moci zlobivé uzly znovu připojit (výchozí: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Při nastavování naslouchacího RPC portu %i pro IPv4 nastala chyba: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Čekat na JSON RPC spojení na <portu> (výchozí: 8332 nebo testnet: 18332) - + Accept command line and JSON-RPC commands Akceptovat příkazy z příkazové řádky a přes JSON-RPC - + Run in the background as a daemon and accept commands Běžet na pozadí jako démon a akceptovat příkazy @@ -2288,12 +2283,12 @@ Adresa: %4 Použít testovací síť (testnet) - + Accept connections from outside (default: 1 if no -proxy or -connect) Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2332,11 +2327,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Nedaří se mi získat zámek na datový adresář %s. Bitcoin pravděpodobně už jednou běží. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Nastala chyba při inicializaci databázového prostředí %s! Řešení: ZAZÁLOHUJ TENTO ADRESÁŘ, a pak v něm smaž vše kromě wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2363,12 +2353,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nastavit maximální velikost prioritních/nízkopoplatkových transakcí v bajtech (výchozí: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Nastavení počtu vláken pro verifikaci skriptů (1-16, 0=automaticky, výchozí: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Tohle je testovací verze – používej ji jen na vlastní riziko, ale rozhodně ji nepoužívej k těžbě nebo pro obchodní aplikace @@ -2408,7 +2393,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Možnosti vytvoření bloku: - + Connect only to the specified node(s) Připojit se pouze k zadanému uzlu (příp. zadaným uzlům) @@ -2428,7 +2413,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chceš přestavět databázi bloků hned teď? - + Error initializing block database Chyba při zakládání databáze bloků @@ -2528,7 +2513,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Hledat uzly přes DNS (výchozí: 1, pokud není zadáno -connect) - + + Generate coins (default: 0) + Generovat mince (výchozí: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Kolik bloků při startu zkontrolovat (výchozí: 288, 0 = všechny) @@ -2538,7 +2528,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Jak moc důkladná má být verifikace bloků (0-4, výchozí: 3) - + + Not enough file descriptors available. + Je nedostatek deskriptorů souborů. + + + Rebuild block chain index from current blk000??.dat files Znovu vytvořit index řetězce bloků z aktuálních blk000??.dat souborů @@ -2558,12 +2553,17 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Kontroluji peněženku... - + Imports blocks from external blk000??.dat file Importovat bloky z externího souboru blk000??.dat - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Nastavení počtu vláken pro verifikaci skriptů (max. 16, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: 0) + + + Information Informace @@ -2588,7 +2588,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Maximální velikost odesílacího bufferu pro každé spojení, <n>*1000 bajtů (výchozí: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Uznávat pouze řetěz bloků, který odpovídá vnitřním kontrolním bodům (výchozí: 1) @@ -2703,12 +2703,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Heslo pro JSON-RPC spojení - + Allow JSON-RPC connections from specified IP address Povolit JSON-RPC spojení ze specifikované IP adresy - + Send commands to node running on <ip> (default: 127.0.0.1) Posílat příkazy uzlu běžícím na <ip> (výchozí: 127.0.0.1) @@ -2748,12 +2748,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Soubor se serverovým soukromým klíčem (výchozí: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akceptovatelné šifry (výchozí: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Tato nápověda @@ -2768,12 +2768,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Připojit se přes socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Povolit DNS dotazy pro -addnode (přidání uzlu), -seednode a -connect (připojení) - + Loading addresses... Načítám adresy... @@ -2788,12 +2788,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chyba při načítání wallet.dat: peněženka vyžaduje novější verzi Bitcoinu - + Wallet needed to be rewritten: restart Bitcoin to complete Soubor s peněženkou potřeboval přepsat: restartuj Bitcoin, aby se operace dokončila - + Error loading wallet.dat Chyba při načítání wallet.dat @@ -2803,7 +2803,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Neplatná -proxy adresa: '%s' - + Unknown network specified in -onlynet: '%s' V -onlynet byla uvedena neznámá síť: '%s' @@ -2823,7 +2823,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nemohu přeložit -externalip adresu: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Neplatná částka pro -paytxfee=<částka>: '%s' @@ -2843,7 +2843,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Načítám index bloků... - + Add a node to connect to and attempt to keep the connection open Přidat uzel, ke kterému se připojit a snažit se spojení udržet @@ -2853,7 +2853,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nedaří se mi připojit na %s na tomhle počítači. Bitcoin už pravděpodobně jednou běží. - + Fee per KB to add to transactions you send Poplatek za kB, který se přidá ke každé odeslané transakci @@ -2863,15 +2863,10 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Načítám peněženku... - + Cannot downgrade wallet Nemohu převést peněženku do staršího formátu - - - Cannot initialize keypool - Nemohu inicializovat zásobník klíčů - Cannot write default address @@ -2883,22 +2878,22 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Přeskenovávám... - + Done loading Načítání dokončeno - + To use the %s option K použití volby %s - + Error Chyba - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index e51229085..862c23c2d 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... Cysoni â'r rhwydwaith... - + &Overview &Trosolwg @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 Mae'r waled <b>wedi'i amgryptio</b> ac <b>ar glo</b> ar hyn o bryd - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index e05c1f4c9..702a1598a 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -323,17 +323,17 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open BitcoinGUI - + Sign &message... Underskriv besked... - + Synchronizing with network... Synkroniserer med netværk... - + &Overview Oversigt @@ -408,7 +408,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Skift adgangskode... - + Importing blocks from disk... Importerer blokke fra disken... @@ -418,7 +418,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Genindekserer blokke på disken... - + Send coins to a Bitcoin address Send bitcoins til en Bitcoin-adresse @@ -453,18 +453,18 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Efterprøv besked... - - + + Bitcoin Bitcoin - + Wallet Tegnebog - + &Send Send @@ -540,7 +540,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open Bitcoin-klient - + %n active connection(s) to Bitcoin network %n aktiv(e) forbindelse(r) til Bitcoin-netværket%n aktiv(e) forbindelse(r) til Bitcoin-netværket @@ -670,7 +670,7 @@ Adresse: %4 Tegnebog er <b>krypteret</b> og i øjeblikket <b>låst</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Der opstod en fatal fejl. Bitcoin kan ikke længere fortsætte sikkert og vil afslutte. @@ -809,8 +809,8 @@ Adresse: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Valgfrit transaktionsgebyr pr. kB, der hjælper dine transaktioner med at blive behandlet hurtigt. De fleste transaktioner er på 1 kB. Gebyr på 0,01 anbefales. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Valgfrit transaktionsgebyr pr. kB, der hjælper dine transaktioner med at blive behandlet hurtigt. De fleste transaktioner er på 1 kB. @@ -2135,12 +2135,17 @@ Adresse: %4 WalletView - + + &Export + Eksporter + + + Export the data in the current tab to a file Eksportér den aktuelle visning til en fil - + Backup Wallet Sikkerhedskopier tegnebog @@ -2173,12 +2178,12 @@ Adresse: %4 bitcoin-core - + Bitcoin version Bitcoin-version - + Usage: Anvendelse: @@ -2188,7 +2193,7 @@ Adresse: %4 Send kommando til -server eller bitcoind - + List commands Liste over kommandoer @@ -2198,7 +2203,7 @@ Adresse: %4 Få hjælp til en kommando - + Options: Indstillinger: @@ -2213,17 +2218,7 @@ Adresse: %4 Angiv pid-fil (default: bitcoind.pid) - - Generate coins - Generer bitcoins - - - - Don't generate coins - Generer ikke bitcoins - - - + Specify data directory Angiv datakatalog @@ -2233,7 +2228,7 @@ Adresse: %4 Angiv databasecachestørrelse i megabytes (standard: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Lyt til forbindelser på <port> (standard: 8333 eller testnetværk: 18333) @@ -2243,7 +2238,7 @@ Adresse: %4 Oprethold højest <n> forbindelser til andre i netværket (standard: 125) - + Connect to a node to retrieve peer addresses, and disconnect Forbind til en knude for at modtage adresse, og afbryd @@ -2263,22 +2258,22 @@ Adresse: %4 Antal sekunder dårlige forbindelser skal vente før reetablering (standard: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Der opstod en fejl ved angivelse af RPC-porten %u til at lytte på IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Lyt til JSON-RPC-forbindelser på <port> (standard: 8332 eller testnetværk: 18332) - + Accept command line and JSON-RPC commands Accepter kommandolinje- og JSON-RPC-kommandoer - + Run in the background as a daemon and accept commands Kør i baggrunden som en service, og accepter kommandoer @@ -2288,12 +2283,12 @@ Adresse: %4 Brug testnetværket - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepter forbindelser udefra (standard: 1 hvis hverken -proxy eller -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2332,11 +2327,6 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Kan ikke opnå lås på datakatalog %s. Bitcoin er sandsynligvis allerede startet. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Klargøring af databasemiljø %s mislykkedes! For at genskabe, SIKKERHEDSKOPIER KATALOGET, fjern dernæst alt med undtagelse af wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2363,12 +2353,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Angiv maksimumstørrelse for høj prioritet/lavt gebyr-transaktioner i bytes (standard: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Angiv nummeret af skriptefterprøvningstråde (1-16, 0=automatisk, standard: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Dette er en foreløbig testudgivelse - brug på eget ansvar - brug ikke til udvinding eller handelsprogrammer @@ -2408,7 +2393,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blokoprettelsestilvalg: - + Connect only to the specified node(s) Tilslut kun til de(n) angivne knude(r) @@ -2428,7 +2413,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Ønsker du at genbygge blokdatabasen nu? - + Error initializing block database Klargøring af blokdatabase mislykkedes @@ -2528,7 +2513,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Find ligeværdige ved DNS-opslag (standard: 1 hvis ikke -connect) - + + Generate coins (default: 0) + Generer bitcoins (standard: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Antal blokke som tjekkes ved opstart (0=alle, standard: 288) @@ -2538,7 +2528,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Grundighed af efterprøvning af blokke (0-4, standard: 3) - + + Not enough file descriptors available. + For få tilgængelige fildeskriptorer. + + + Rebuild block chain index from current blk000??.dat files Genbyg blokkædeindeks fra nuværende blk000??.dat filer @@ -2558,12 +2553,17 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Efterprøver tegnebog... - + Imports blocks from external blk000??.dat file Importerer blokke fra ekstern blk000??.dat fil - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Angiv nummeret af skriptefterprøvningstråde (op til 16, 0 = automatisk, <0 = efterlad det antal kerner tilgængelige, standard: 0) + + + Information Information @@ -2588,7 +2588,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Maksimum for afsendelsesbuffer pr. forbindelse, <n>*1000 bytes (standard: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Accepter kun blokkæde, som matcher indbyggede kontrolposter (standard: 1) @@ -2703,12 +2703,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Adgangskode til JSON-RPC-forbindelser - + Allow JSON-RPC connections from specified IP address Tillad JSON-RPC-forbindelser fra bestemt IP-adresse - + Send commands to node running on <ip> (default: 127.0.0.1) Send kommandoer til knude, der kører på <ip> (standard: 127.0.0.1) @@ -2748,12 +2748,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Serverens private nøgle (standard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Acceptable ciphers (standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Denne hjælpebesked @@ -2768,12 +2768,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Tilslut via SOCKS-proxy - + Allow DNS lookups for -addnode, -seednode and -connect Tillad DNS-opslag for -addnode, -seednode og -connect - + Loading addresses... Indlæser adresser... @@ -2788,12 +2788,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Fejl ved indlæsning af wallet.dat: Tegnebog kræver en nyere version af Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Det var nødvendigt at genskrive tegnebogen: genstart Bitcoin for at gennemføre - + Error loading wallet.dat Fejl ved indlæsning af wallet.dat @@ -2803,7 +2803,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Ugyldig -proxy adresse: '%s' - + Unknown network specified in -onlynet: '%s' Ukendt netværk anført i -onlynet: '%s' @@ -2823,7 +2823,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Kan ikke finde -externalip adressen: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ugyldigt beløb for -paytxfee=<amount>: '%s' @@ -2843,7 +2843,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Indlæser blokindeks... - + Add a node to connect to and attempt to keep the connection open Tilføj en knude til at forbinde til og forsøg at holde forbindelsen åben @@ -2853,7 +2853,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Kunne ikke tildele %s på denne computer. Bitcoin kører sikkert allerede. - + Fee per KB to add to transactions you send Gebyr pr. kB, som skal tilføjes til transaktioner, du sender @@ -2863,15 +2863,10 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Indlæser tegnebog... - + Cannot downgrade wallet Kan ikke nedgradere tegnebog - - - Cannot initialize keypool - Kan ikke påbegynde nøglepulje - Cannot write default address @@ -2883,22 +2878,22 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Genindlæser... - + Done loading Indlæsning gennemført - + To use the %s option For at bruge %s mulighed - + Error Fejl - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index ce3a7f396..d5dbff0a9 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -323,17 +323,17 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open BitcoinGUI - + Sign &message... Nachricht s&ignieren... - + Synchronizing with network... Synchronisiere mit Netzwerk... - + &Overview &Übersicht @@ -408,7 +408,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Passphrase &ändern... - + Importing blocks from disk... Importiere Blöcke von Laufwerk... @@ -418,7 +418,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Reindiziere Blöcke auf Laufwerk... - + Send coins to a Bitcoin address Bitcoins an eine Bitcoin-Adresse überweisen @@ -453,18 +453,18 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Nachricht &verifizieren... - - + + Bitcoin Bitcoin - + Wallet Brieftasche - + &Send Überweisen @@ -540,7 +540,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open Bitcoin-Client - + %n active connection(s) to Bitcoin network %n aktive Verbindung zum Bitcoin-Netzwerk%n aktive Verbindungen zum Bitcoin-Netzwerk @@ -669,7 +669,7 @@ Adresse: %4 Brieftasche ist <b>verschlüsselt</b> und aktuell <b>gesperrt</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ein schwerer Fehler ist aufgetreten. Bitcoin kann nicht stabil weiter ausgeführt werden und wird beendet. @@ -808,8 +808,8 @@ Adresse: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Optionale Transaktionsgebühr pro kB, die sicherstellt, dass Ihre Transaktionen schnell bearbeitet werden. Die meisten Transaktionen sind 1 kB groß. Eine Gebühr von 0.01 BTC wird empfohlen. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optionale Transaktionsgebühr pro KB, die sicherstellt, dass Ihre Transaktionen schnell bearbeitet werden. Die meisten Transaktionen sind 1 kB groß. @@ -2134,12 +2134,17 @@ Adresse: %4 WalletView - + + &Export + E&xportieren + + + Export the data in the current tab to a file Daten der aktuellen Ansicht in eine Datei exportieren - + Backup Wallet Brieftasche sichern @@ -2172,12 +2177,12 @@ Adresse: %4 bitcoin-core - + Bitcoin version Bitcoin-Version - + Usage: Benutzung: @@ -2187,7 +2192,7 @@ Adresse: %4 Befehl an -server oder bitcoind senden - + List commands Befehle auflisten @@ -2197,7 +2202,7 @@ Adresse: %4 Hilfe zu einem Befehl erhalten - + Options: Optionen: @@ -2212,17 +2217,7 @@ Adresse: %4 PID-Datei festlegen (Standard: bitcoind.pid) - - Generate coins - Bitcoins generieren - - - - Don't generate coins - Keine Bitcoins generieren - - - + Specify data directory Datenverzeichnis festlegen @@ -2232,7 +2227,7 @@ Adresse: %4 Größe des Datenbankcaches in MB festlegen (Standard: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) <port> nach Verbindungen abhören (Standard: 8333 oder Testnetz: 18333) @@ -2242,7 +2237,7 @@ Adresse: %4 Maximal <n> Verbindungen zu Gegenstellen aufrechterhalten (Standard: 125) - + Connect to a node to retrieve peer addresses, and disconnect Mit dem Knoten verbinden um Adressen von Gegenstellen abzufragen, danach trennen @@ -2262,22 +2257,22 @@ Adresse: %4 Anzahl Sekunden, während denen sich nicht konform verhaltenden Gegenstellen die Wiederverbindung verweigert wird (Standard: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Beim Einrichten des abzuhörenden RPC-Ports %u für IPv4 ist ein Fehler aufgetreten: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) <port> nach JSON-RPC-Verbindungen abhören (Standard: 8332 oder Testnetz: 18332) - + Accept command line and JSON-RPC commands Kommandozeilenbefehle und JSON-RPC-Befehle annehmen - + Run in the background as a daemon and accept commands Als Hintergrunddienst starten und Befehle annehmen @@ -2287,12 +2282,12 @@ Adresse: %4 Das Testnetz verwenden - + Accept connections from outside (default: 1 if no -proxy or -connect) Eingehende Verbindungen annehmen (Standard: 1, wenn nicht -proxy oder -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2331,11 +2326,6 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde Bitcoin bereits gestartet. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Fehler beim Initialisieren der Datenbankumgebung %s! Zur Wiederherstellung, sichern Sie dieses Verzeichnis und löschen darin dann alles, außer wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2362,12 +2352,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Maximale Größe von "high-priority/low-fee"-Transaktionen in Byte festlegen (Standard: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (1-16, 0 = automatisch, Standard: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Dies ist eine Vorab-Testversion - Verwendung auf eigene Gefahr - nicht für Mining- oder Handelsanwendungen nutzen! @@ -2407,7 +2392,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Blockerzeugungsoptionen: - + Connect only to the specified node(s) Nur mit dem/den angegebenen Knoten verbinden @@ -2427,7 +2412,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Möchten Sie die Blockdatenbank nun neu aufbauen? - + Error initializing block database Fehler beim Initialisieren der Blockdatenbank @@ -2527,7 +2512,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Gegenstellen via DNS-Namensauflösung finden (Standard: 1, außer bei -connect) - + + Generate coins (default: 0) + Bitcoins generieren (Standard: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Wieviele Blöcke sollen beim Starten geprüft werden (Standard: 288, 0 = alle) @@ -2537,7 +2527,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Wie gründlich soll die Blockprüfung sein (0-4, Standard: 3) - + + Not enough file descriptors available. + Nicht genügend File-Deskriptoren verfügbar. + + + Rebuild block chain index from current blk000??.dat files Blockkettenindex aus aktuellen Dateien blk000??.dat wiederaufbauen @@ -2557,12 +2552,17 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Verifiziere Brieftasche... - + Imports blocks from external blk000??.dat file Blöcke aus externer Datei blk000??.dat importieren - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (bis zu 16, 0 = automatisch, <0 = soviele Kerne frei lassen, Standard: 0) + + + Information Hinweis @@ -2587,7 +2587,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Maximale Größe, <n> * 1000 Byte, des Sendepuffers pro Verbindung (Standard: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Blockkette nur akzeptieren, wenn sie mit den integrierten Prüfpunkten übereinstimmt (Standard: 1) @@ -2702,12 +2702,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Passwort für JSON-RPC-Verbindungen - + Allow JSON-RPC connections from specified IP address JSON-RPC-Verbindungen von der angegebenen IP-Adresse erlauben - + Send commands to node running on <ip> (default: 127.0.0.1) Sende Befehle an Knoten <ip> (Standard: 127.0.0.1) @@ -2747,12 +2747,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Privater Serverschlüssel (Standard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akzeptierte Chiffren (Standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Dieser Hilfetext @@ -2767,12 +2767,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Verbindung über SOCKS-Proxy herstellen - + Allow DNS lookups for -addnode, -seednode and -connect Erlaube DNS-Namensauflösung für -addnode, -seednode und -connect - + Loading addresses... Lade Adressen... @@ -2787,12 +2787,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Fehler beim Laden von wallet.dat: Brieftasche benötigt neuere Version von Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Brieftasche musste neu geschrieben werden: Starten Sie Bitcoin zur Fertigstellung neu - + Error loading wallet.dat Fehler beim Laden von wallet.dat (Brieftasche) @@ -2802,7 +2802,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Ungültige Adresse in -proxy: '%s' - + Unknown network specified in -onlynet: '%s' Unbekannter Netztyp in -onlynet angegeben: '%s' @@ -2822,14 +2822,14 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Kann Adresse in -externalip nicht auflösen: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - Falscher Betrag für -paytxfee=<Betrag>: '%s' + Ungültiger Betrag für -paytxfee=<Betrag>: '%s' Invalid amount - Ungültige Angabe + Ungültiger Betrag @@ -2842,7 +2842,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Lade Blockindex... - + Add a node to connect to and attempt to keep the connection open Mit dem Knoten verbinden und versuchen die Verbindung aufrecht zu halten @@ -2852,7 +2852,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Kann auf diesem Computer nicht an %s binden. Evtl. wurde Bitcoin bereits gestartet. - + Fee per KB to add to transactions you send Gebühr pro KB, die gesendeten Transaktionen hinzugefügt wird @@ -2862,15 +2862,10 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Lade Brieftasche... - + Cannot downgrade wallet Brieftasche kann nicht auf eine ältere Version herabgestuft werden - - - Cannot initialize keypool - Schlüsselpool kann nicht initialisiert werden - Cannot write default address @@ -2882,22 +2877,22 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Durchsuche erneut... - + Done loading Laden abgeschlossen - + To use the %s option Zur Nutzung der %s Option - + Error Fehler - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 3587f3467..f7073c465 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -103,12 +103,12 @@ This product includes software developed by the OpenSSL Project for use in the O Verify a message to ensure it was signed with a specified Bitcoin address - + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως ανήκει μια συγκεκριμένη διεύθυνση Bitcoin &Verify Message - + &Επιβεβαίωση μηνύματος @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Υπογραφή &Μηνύματος... - + Synchronizing with network... Συγχρονισμός με το δίκτυο... - + &Overview &Επισκόπηση @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Άλλαξε κωδικο πρόσβασης - + Importing blocks from disk... @@ -413,9 +413,9 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address - + Στείλε νομισματα σε μια διεύθυνση bitcoin @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Επιβεβαίωση μηνύματος - - + + Bitcoin Bitcoin - + Wallet Πορτοφόλι - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O Πελάτης Bitcoin - + %n active connection(s) to Bitcoin network %n ενεργή σύνδεση στο δίκτυο Bitcoin%n ενεργές συνδέσεις στο δίκτυο Βitcoin @@ -646,7 +646,7 @@ Address: %4 URI handling - + Χειρισμός URI @@ -665,7 +665,7 @@ Address: %4 Το πορτοφόλι είναι <b>κρυπτογραφημένο</b> και <b>κλειδωμένο</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -752,7 +752,7 @@ Address: %4 Bitcoin-Qt - + bitcoin-qt @@ -804,8 +804,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Η προαιρετική αμοιβή για κάθε kB επισπεύδει την επεξεργασία των συναλλαγών σας. Οι περισσότερες συναλλαγές είναι 1 kB. Προτείνεται αμοιβή 0.01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -820,7 +820,7 @@ Address: %4 &Start Bitcoin on system login - + &Έναρξη του Βιtcoin κατά την εκκίνηση του συστήματος @@ -870,7 +870,7 @@ Address: %4 &Port: - + &Θύρα: @@ -895,7 +895,7 @@ Address: %4 Show only a tray icon after minimizing the window. - + Εμφάνιση μόνο εικονιδίου στην περιοχή ειδοποιήσεων κατά την ελαχιστοποίηση @@ -910,12 +910,12 @@ Address: %4 M&inimize on close - + Ε&λαχιστοποίηση κατά το κλείσιμο &Display - + %Απεικόνιση @@ -930,7 +930,7 @@ Address: %4 &Unit to show amounts in: - + &Μονάδα μέτρησης: @@ -945,27 +945,27 @@ Address: %4 &Display addresses in transaction list - + Εμφάνιση διευθύνσεων στη λίστα συναλλαγών &OK - + &ΟΚ &Cancel - + &Ακύρωση &Apply - + &Εφαρμογή default - + προεπιλογή @@ -1220,7 +1220,7 @@ Address: %4 &Show - + &Εμφάνιση @@ -1305,7 +1305,7 @@ Address: %4 Clear &All - + Καθαρισμός &Όλων @@ -1525,12 +1525,12 @@ Address: %4 Clear &All - + Καθαρισμός &Όλων &Verify Message - + &Επιβεβαίωση μηνύματος @@ -1571,13 +1571,13 @@ Address: %4 Enter Bitcoin signature - + Εισαγωγή υπογραφής Bitcoin The entered address is invalid. - + Η διεύθυνση που εισήχθη είναι λάθος. @@ -1585,7 +1585,7 @@ Address: %4 Please check the address and try again. - + Παρακαλούμε ελέγξτε την διεύθυνση και δοκιμάστε ξανά. @@ -1606,23 +1606,23 @@ Address: %4 Message signing failed. - + Η υπογραφή του μηνύματος απέτυχε. Message signed. - + Μήνυμα υπεγράφη. The signature could not be decoded. - + Η υπογραφή δεν μπόρεσε να αποκρυπτογραφηθεί. Please check the signature and try again. - + Παρακαλούμε ελέγξτε την υπογραφή και δοκιμάστε ξανά. @@ -1632,12 +1632,12 @@ Address: %4 Message verification failed. - + Η επιβεβαίωση του μηνύματος απέτυχε Message verified. - + Μήνυμα επιβεβαιώθηκε. @@ -1663,7 +1663,7 @@ Address: %4 %1/offline - + %1/χωρίς σύνδεση; @@ -1693,7 +1693,7 @@ Address: %4 Source - + Πηγή @@ -1769,12 +1769,12 @@ Address: %4 Comment - + Σχόλιο: Transaction ID - + ID Συναλλαγής: @@ -1784,12 +1784,12 @@ Address: %4 Debug information - + Πληροφορίες αποσφαλμάτωσης Transaction - + Συναλλαγή @@ -2130,12 +2130,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Εξαγωγή δεδομένων καρτέλας σε αρχείο - + Backup Wallet @@ -2168,12 +2173,12 @@ Address: %4 bitcoin-core - + Bitcoin version Έκδοση Bitcoin - + Usage: Χρήση: @@ -2183,7 +2188,7 @@ Address: %4 Αποστολή εντολής στον εξυπηρετητή ή στο bitcoind - + List commands Λίστα εντολών @@ -2193,7 +2198,7 @@ Address: %4 Επεξήγηση εντολής - + Options: Επιλογές: @@ -2208,17 +2213,7 @@ Address: %4 Ορίστε αρχείο pid (προεπιλογή: bitcoind.pid) - - Generate coins - Δημιουργία νομισμάτων - - - - Don't generate coins - Άρνηση δημιουργίας νομισμάτων - - - + Specify data directory Ορισμός φακέλου δεδομένων @@ -2228,7 +2223,7 @@ Address: %4 Όρισε το μέγεθος της βάσης προσωρινής αποθήκευσης σε megabytes(προεπιλογή:25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Εισερχόμενες συνδέσεις στη θύρα <port> (προεπιλογή: 8333 ή στο testnet: 18333) @@ -2238,14 +2233,14 @@ Address: %4 Μέγιστες αριθμός συνδέσεων με τους peers <n> (προεπιλογή: 125) - + Connect to a node to retrieve peer addresses, and disconnect Specify your own public address - + Διευκρινίστε τη δικιά σας δημόσια διεύθυνση. @@ -2258,22 +2253,22 @@ Address: %4 Δευτερόλεπτα πριν επιτραπεί ξανά η σύνδεση των προβληματικών peers (προεπιλογή: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Εισερχόμενες συνδέσεις JSON-RPC στη θύρα <port> (προεπιλογή: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Αποδοχή εντολών κονσόλας και JSON-RPC - + Run in the background as a daemon and accept commands Εκτέλεση στο παρασκήνιο κι αποδοχή εντολών @@ -2283,12 +2278,12 @@ Address: %4 Χρήση του δοκιμαστικού δικτύου - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2317,11 +2312,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2348,12 +2338,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2393,7 +2378,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) Σύνδεση μόνο με ορισμένους κόμβους @@ -2413,7 +2398,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2513,7 +2498,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2523,7 +2513,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2543,12 +2538,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2573,7 +2573,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2688,12 +2688,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Κωδικός για τις συνδέσεις JSON-RPC - + Allow JSON-RPC connections from specified IP address Αποδοχή συνδέσεων JSON-RPC από συγκεκριμένη διεύθυνση IP - + Send commands to node running on <ip> (default: 127.0.0.1) Αποστολή εντολών στον κόμβο <ip> (προεπιλογή: 127.0.0.1) @@ -2733,12 +2733,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Προσωπικό κλειδί του διακομιστή (προεπιλογή: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Αποδεκτά κρυπτογραφήματα (προεπιλογή: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Αυτό το κείμενο βοήθειας @@ -2753,12 +2753,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Σύνδεση μέσω διαμεσολαβητή socks - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Φόρτωση διευθύνσεων... @@ -2773,12 +2773,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Σφάλμα φόρτωσης wallet.dat: Το Πορτοφόλι απαιτεί μια νεότερη έκδοση του Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Απαιτείται η επανεγγραφή του Πορτοφολιού, η οποία θα ολοκληρωθεί στην επανεκκίνηση του Bitcoin - + Error loading wallet.dat Σφάλμα φόρτωσης αρχείου wallet.dat @@ -2788,7 +2788,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2808,7 +2808,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2828,7 +2828,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Φόρτωση ευρετηρίου μπλοκ... - + Add a node to connect to and attempt to keep the connection open Προσέθεσε ένα κόμβο για σύνδεση και προσπάθησε να κρατήσεις την σύνδεση ανοιχτή @@ -2838,7 +2838,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send Αμοιβή ανά KB που θα προστίθεται στις συναλλαγές που στέλνεις @@ -2848,15 +2848,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Φόρτωση πορτοφολιού... - + Cannot downgrade wallet Δεν μπορώ να υποβαθμίσω το πορτοφόλι - - - Cannot initialize keypool - Δεν μπορώ αν αρχικοποιήσω την λίστα κλειδιών - Cannot write default address @@ -2868,22 +2863,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ανίχνευση... - + Done loading Η φόρτωση ολοκληρώθηκε - + To use the %s option Χρήση της %s επιλογής - + Error Σφάλμα - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 151e19bbe..2006a5296 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -2161,6 +2161,14 @@ Address: %4 to + + WalletModel + + + Send Coins + Send Coins + + WalletView @@ -2212,12 +2220,12 @@ Address: %4 Bitcoin version - + Usage: Usage: - + Send command to -server or bitcoind Send command to -server or bitcoind @@ -2227,17 +2235,17 @@ Address: %4 List commands - + Get help for a command Get help for a command - + Options: Options: - + Specify configuration file (default: bitcoin.conf) Specify configuration file (default: bitcoin.conf) @@ -2252,7 +2260,7 @@ Address: %4 Specify data directory - + Set database cache size in megabytes (default: 25) Set database cache size in megabytes (default: 25) @@ -2267,12 +2275,12 @@ Address: %4 Maintain at most <n> connections to peers (default: 125) - + Connect to a node to retrieve peer addresses, and disconnect Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address Specify your own public address @@ -2282,7 +2290,7 @@ Address: %4 Threshold for disconnecting misbehaving peers (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2302,17 +2310,17 @@ Address: %4 Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands Run in the background as a daemon and accept commands - + Use the test network Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2466,11 +2474,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Error: Disk space is low! - - - Error: Transaction creation failed! - Error: Transaction creation failed! - Error: Wallet locked, unable to create transaction! @@ -2557,7 +2560,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. How thorough the block verification is (0-4, default: 3) - + Not enough file descriptors available. Not enough file descriptors available. @@ -2572,7 +2575,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Set the number of threads to service RPC calls (default: 4) - + Verifying blocks... Verifying blocks... @@ -2582,17 +2585,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verifying wallet... - + Imports blocks from external blk000??.dat file Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Information @@ -2601,6 +2604,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Invalid amount for -mintxfee=<amount>: '%s' + Maintain a full transaction index (default: 0) @@ -2676,6 +2689,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + Signing transaction failed + Specify connection timeout in milliseconds (default: 5000) @@ -2687,7 +2705,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. System error: - + + Transaction amount too small + Transaction amount too small + + + + Transaction amounts must be positive + Transaction amounts must be positive + + + + Transaction too large + Transaction too large + + + Use UPnP to map the listening port (default: 0) Use UPnP to map the listening port (default: 0) @@ -2727,32 +2760,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat corrupt, salvage failed - + Password for JSON-RPC connections Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) Set key pool size to <n> (default: 100) @@ -2762,12 +2795,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescan the block chain for missing wallet transactions - + Use OpenSSL (https) for JSON-RPC connections Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) Server certificate file (default: server.cert) @@ -2777,22 +2810,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Server private key (default: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy Connect through socks proxy @@ -2802,12 +2835,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Loading addresses... - + Error loading wallet.dat: Wallet corrupted Error loading wallet.dat: Wallet corrupted @@ -2817,22 +2850,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error loading wallet.dat: Wallet requires newer version of Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat Error loading wallet.dat - + Invalid -proxy address: '%s' Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' Unknown network specified in -onlynet: '%s' @@ -2842,7 +2875,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Unknown -socks proxy version requested: %i - + Cannot resolve -bind address: '%s' Cannot resolve -bind address: '%s' @@ -2852,7 +2885,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot resolve -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Invalid amount for -paytxfee=<amount>: '%s' @@ -2862,17 +2895,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid amount - + Insufficient funds Insufficient funds - + Loading block index... Loading block index... - + Add a node to connect to and attempt to keep the connection open Add a node to connect to and attempt to keep the connection open @@ -2882,17 +2915,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Unable to bind to %s on this computer. Bitcoin is probably already running. - + Fee per KB to add to transactions you send Fee per KB to add to transactions you send - + Loading wallet... Loading wallet... - + Cannot downgrade wallet Cannot downgrade wallet @@ -2902,22 +2935,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot write default address - + Rescanning... Rescanning... - + Done loading Done loading - + To use the %s option To use the %s option - + Error Error diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index 298c16323..1e2281f75 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Subskribu &mesaĝon... - + Synchronizing with network... Sinkronigante kun reto... - + &Overview &Superrigardo @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Anstataŭigu pasfrazon... - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Kontrolu mesaĝon... - - + + Bitcoin - + Wallet Monujo - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 Monujo estas <b>ĉifrita</b> kaj nun <b>ŝlosita</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version Bitcoin-a versio - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands Listigu instrukciojn @@ -2189,7 +2194,7 @@ Address: %4 - + Options: Opcioj: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - Generu monerojn - - - - Don't generate coins - Ne generu monerojn - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Ŝarĝante adresojn... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ŝarĝante blok-indekson... - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ŝarĝante monujon... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading Ŝarĝado finitas - + To use the %s option Por uzi la opcion %s - + Error Eraro - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 809d8c133..ef38c0f64 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -326,17 +326,17 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. BitcoinGUI - + Sign &message... Firmar &mensaje... - + Synchronizing with network... Sincronizando con la red… - + &Overview &Vista general @@ -411,7 +411,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.&Cambiar la contraseña… - + Importing blocks from disk... Importando bloques de disco... @@ -421,7 +421,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Reindexando bloques en disco... - + Send coins to a Bitcoin address Enviar monedas a una dirección Bitcoin @@ -456,18 +456,18 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.&Verificar mensaje... - - + + Bitcoin Bitcoin - + Wallet Monedero - + &Send &Enviar @@ -543,7 +543,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard.Cliente Bitcoin - + %n active connection(s) to Bitcoin network %n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin @@ -673,7 +673,7 @@ Dirección: %4 El monedero está <b>cifrado</b> y actualmente <b>bloqueado</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ha ocurrido un error crítico. Bitcoin ya no puede continuar con seguridad y se cerrará. @@ -812,8 +812,8 @@ Dirección: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Tarifa de transacción por KB opcional que ayuda a asegurarse de que sus transacciones se procesan rápidamente. La mayoría de las transacciones son de 1 KB. Tarifa de 0,01 recomendada. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Tarifa de transacción opcional por kB que ayuda a asegurar que tus transacciones sean procesadas rápidamente. La mayoría de transacciones son de 1kB. @@ -2138,12 +2138,17 @@ Dirección: %4 WalletView - + + &Export + &Exportar + + + Export the data in the current tab to a file Exportar a un archivo los datos de esta pestaña - + Backup Wallet Respaldo de monedero @@ -2176,12 +2181,12 @@ Dirección: %4 bitcoin-core - + Bitcoin version Versión de Bitcoin - + Usage: Uso: @@ -2191,7 +2196,7 @@ Dirección: %4 Envíar comando a -server o bitcoind - + List commands Muestra comandos @@ -2203,7 +2208,7 @@ Dirección: %4 - + Options: Opciones: @@ -2221,17 +2226,7 @@ Dirección: %4 - - Generate coins - Generar monedas - - - - Don't generate coins - No generar monedas - - - + Specify data directory Especificar directorio para los datos @@ -2241,7 +2236,7 @@ Dirección: %4 Establecer el tamaño de caché de la base de datos en megabytes (predeterminado: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Escuchar conexiones en <puerto> (predeterminado: 8333 o testnet: 18333) @@ -2251,7 +2246,7 @@ Dirección: %4 Mantener como máximo <n> conexiones a pares (predeterminado: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conectar a un nodo para obtener direcciones de pares y desconectar @@ -2271,23 +2266,23 @@ Dirección: %4 Número de segundos en que se evita la reconexión de pares con mal comportamiento (predeterminado: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Ha ocurrido un error al configurar el puerto RPC %u para escucha en IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Escuchar conexiones JSON-RPC en <puerto> (predeterminado: 8332 o testnet:18332) - + Accept command line and JSON-RPC commands Aceptar comandos consola y JSON-RPC - + Run in the background as a daemon and accept commands Correr como demonio y aceptar comandos @@ -2299,12 +2294,12 @@ Dirección: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2343,11 +2338,6 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. No se puede bloquear el directorio de datos %s. Probablemente Bitcoin ya se está ejecutando. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - ¡Error al inicializar el entorno de base de datos %s! Para restaurarlo, HAGA UNA COPIA DE SEGURIDAD DEL DIRECTORIO y borre todos sus contenidos excepto wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2374,12 +2364,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Establecer el tamaño máximo de las transacciones de alta prioridad/comisión baja en bytes (predeterminado:27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Establecer el número de hilos para la verificación de scripts (1-16, 0=automático, predeterminado: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Esta es una versión de pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería. @@ -2419,7 +2404,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Opciones de creación de bloques: - + Connect only to the specified node(s) Conectar sólo a los nodos (o nodo) especificados @@ -2439,7 +2424,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. ¿Quieres reconstruir la base de datos de bloques ahora? - + Error initializing block database Error al inicializar la base de datos de bloques @@ -2539,7 +2524,12 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Encontrar pares mediante búsqueda de DNS (predeterminado: 1 salvo con -connect) - + + Generate coins (default: 0) + Generar monedas (por defecto: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Cuántos bloques comprobar al iniciar (predeterminado: 288, 0 = todos) @@ -2549,7 +2539,12 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Como es de exhaustiva la verificación de bloques (0-4, por defecto 3) - + + Not enough file descriptors available. + No hay suficientes descriptores de archivo disponibles. + + + Rebuild block chain index from current blk000??.dat files Reconstruir el índice de la cadena de bloques a partir de los archivos blk000??.dat actuales @@ -2569,12 +2564,17 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verificando monedero... - + Imports blocks from external blk000??.dat file Importa los bloques desde un archivo blk000??.dat externo - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Configura el número de hilos para el script de verificación (hasta 16, 0 = auto, <0 = leave that many cores free, por fecto: 0) + + + Information Información @@ -2599,7 +2599,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Búfer de recepción máximo por conexión, , <n>*1000 bytes (predeterminado: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Aceptar solamente cadena de bloques que concuerde con los puntos de control internos (predeterminado: 1) @@ -2716,13 +2716,13 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address Permitir conexiones JSON-RPC desde la dirección IP especificada - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comando al nodo situado en <ip> (predeterminado: 127.0.0.1) @@ -2767,13 +2767,13 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrados aceptados (predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Este mensaje de ayuda @@ -2789,12 +2789,12 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Conectar mediante proxy socks - + Allow DNS lookups for -addnode, -seednode and -connect Permitir búsquedas DNS para -addnode, -seednode y -connect - + Loading addresses... Cargando direcciones... @@ -2809,12 +2809,12 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error al cargar wallet.dat: El monedero requiere una versión más reciente de Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete El monedero ha necesitado ser reescrito. Reinicie Bitcoin para completar el proceso - + Error loading wallet.dat Error al cargar wallet.dat @@ -2824,7 +2824,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Dirección -proxy inválida: '%s' - + Unknown network specified in -onlynet: '%s' La red especificada en -onlynet '%s' es desconocida @@ -2844,7 +2844,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No se puede resolver la dirección de -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Cantidad inválida para -paytxfee=<amount>: '%s' @@ -2864,7 +2864,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cargando el índice de bloques... - + Add a node to connect to and attempt to keep the connection open Añadir un nodo al que conectarse y tratar de mantener la conexión abierta @@ -2874,7 +2874,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es posible conectar con %s en este sistema. Probablemente Bitcoin ya está ejecutándose. - + Fee per KB to add to transactions you send Tarifa por KB que añadir a las transacciones que envíe @@ -2884,15 +2884,10 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cargando monedero... - + Cannot downgrade wallet No se puede rebajar el monedero - - - Cannot initialize keypool - No se puede inicializar la reserva de claves - Cannot write default address @@ -2904,22 +2899,22 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescaneando... - + Done loading Generado pero no aceptado - + To use the %s option Para utilizar la opción %s - + Error Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index 0c2d624b2..78d59bd16 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -326,17 +326,17 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. BitcoinGUI - + Sign &message... Firmar &Mensaje... - + Synchronizing with network... Sincronizando con la red... - + &Overview &Vista general @@ -411,7 +411,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.&Cambiar la contraseña... - + Importing blocks from disk... @@ -421,7 +421,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - + Send coins to a Bitcoin address Enviar monedas a una dirección bitcoin @@ -456,18 +456,18 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard. - - + + Bitcoin Bitcoin - + Wallet Cartera - + &Send @@ -543,7 +543,7 @@ Eric Young (eay@cryptsoft.com) y UPnP software escrito por Thomas Bernard.Cliente Bitcoin - + %n active connection(s) to Bitcoin network %n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin @@ -672,7 +672,7 @@ Dirección: %4 La billetera esta <b>codificada</b> y actualmente <b>bloqueda</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -812,8 +812,8 @@ Dirección: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Comisión opcional por kB que ayuda a asegurar que sus transacciones son procesadas rápidamente. La mayoria de transacciones son de 1 KB. Se recomienda comisión de 0.01 + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2138,12 +2138,17 @@ Dirección: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Exportar los datos de la pestaña actual a un archivo - + Backup Wallet @@ -2176,12 +2181,12 @@ Dirección: %4 bitcoin-core - + Bitcoin version Versión Bitcoin - + Usage: Uso: @@ -2192,7 +2197,7 @@ Dirección: %4 - + List commands Muestra comandos @@ -2204,7 +2209,7 @@ Dirección: %4 - + Options: Opciones: @@ -2222,19 +2227,7 @@ Dirección: %4 - - Generate coins - Genera monedas - - - - - Don't generate coins - No generar monedas - - - - + Specify data directory Especifica directorio para los datos @@ -2245,7 +2238,7 @@ Dirección: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) Escuchar por conecciones en <puerto> (Por defecto: 8333 o red de prueba: 18333) @@ -2255,7 +2248,7 @@ Dirección: %4 Mantener al menos <n> conecciones por cliente (por defecto: 125) - + Connect to a node to retrieve peer addresses, and disconnect @@ -2275,23 +2268,23 @@ Dirección: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Escucha conexiones JSON-RPC en el puerto <port> (predeterminado: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Aceptar comandos consola y JSON-RPC - + Run in the background as a daemon and accept commands Correr como demonio y acepta comandos @@ -2303,12 +2296,12 @@ Dirección: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2337,11 +2330,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2368,12 +2356,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2413,7 +2396,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) Conecta solo al nodo especificado @@ -2434,7 +2417,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2534,7 +2517,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2544,7 +2532,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2564,12 +2557,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2594,7 +2592,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2711,13 +2709,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address Permite conexiones JSON-RPC desde la dirección IP especificada - + Send commands to node running on <ip> (default: 127.0.0.1) Envia comando al nodo situado en <ip> (predeterminado: 127.0.0.1) @@ -2763,13 +2761,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrados aceptados (Predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Este mensaje de ayuda @@ -2785,13 +2783,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Conecta mediante proxy socks - + Allow DNS lookups for -addnode, -seednode and -connect Permite búsqueda DNS para addnode y connect - + Loading addresses... Cargando direcciónes... @@ -2806,12 +2804,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error cargando wallet.dat: Billetera necesita una vercion reciente de Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete La billetera necesita ser reescrita: reinicie Bitcoin para completar - + Error loading wallet.dat Error cargando wallet.dat @@ -2821,7 +2819,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Dirección -proxy invalida: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2841,7 +2839,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Cantidad inválida para -paytxfee=<amount>: '%s' @@ -2861,7 +2859,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cargando el index de bloques... - + Add a node to connect to and attempt to keep the connection open Agrega un nodo para conectarse and attempt to keep the connection open @@ -2871,7 +2869,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es posible escuchar en el %s en este ordenador. Probablemente Bitcoin ya se está ejecutando. - + Fee per KB to add to transactions you send Comisión por kB para adicionarla a las transacciones enviadas @@ -2881,15 +2879,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cargando cartera... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2901,22 +2894,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescaneando... - + Done loading Carga completa - + To use the %s option - + Error Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index 71d08f46f..c5ae7b0b2 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -323,17 +323,17 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS BitcoinGUI - + Sign &message... Signeeri &sõnum - + Synchronizing with network... Võrgusünkimine... - + &Overview &Ülevaade @@ -408,7 +408,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS &Salafraasi muutmine - + Importing blocks from disk... Impordi blokid kettalt... @@ -418,7 +418,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Kettal olevate blokkide re-indekseerimine... - + Send coins to a Bitcoin address Saada münte Bitcoini aadressile @@ -453,18 +453,18 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS &Kontrolli sõnumit... - - + + Bitcoin Bitcoin - + Wallet Rahakott - + &Send &Saada @@ -540,7 +540,7 @@ Toode sisaldab OpenSSL Projekti all toodetud tarkvara, mis on kasutamiseks OpenS Bitcoini klient - + %n active connection(s) to Bitcoin network %n aktiivne ühendus Bitcoini võrku%n aktiivset ühendust Bitcoini võrku @@ -669,7 +669,7 @@ Aadress: %4⏎ Rahakott on <b>krüpteeritud</b> ning hetkel <b>suletud</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ilmnes kriitiline tõrge. Bitcoin suletakse turvakaalutluste tõttu. @@ -808,8 +808,8 @@ Aadress: %4⏎ - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Valikuline tehingu lisatasu kB kohta aitab protsessi kiirendada. Enamik tehinguid on 1 kB suured. Soovitatav lisatasu: 0,01 + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2134,12 +2134,17 @@ Aadress: %4⏎ WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet Varundatud Rahakott @@ -2172,12 +2177,12 @@ Aadress: %4⏎ bitcoin-core - + Bitcoin version Bitcoini versioon - + Usage: Kasutus: @@ -2187,7 +2192,7 @@ Aadress: %4⏎ Saada käsklus -serverile või bitcoindile - + List commands Käskluste loetelu @@ -2197,7 +2202,7 @@ Aadress: %4⏎ Käskluste abiinfo - + Options: Valikud: @@ -2212,17 +2217,7 @@ Aadress: %4⏎ Täpsusta PID fail (vaikimisi: bitcoin.pid) - - Generate coins - Müntide genereerimine - - - - Don't generate coins - Ära genereeri münte - - - + Specify data directory Täpsusta andmekataloog @@ -2232,7 +2227,7 @@ Aadress: %4⏎ Sea andmebaasi vahemälu suurus MB (vaikeväärtus: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Kuula ühendusi pordil <port> (vaikeväärtus: 8333 või testnet: 18333) @@ -2242,7 +2237,7 @@ Aadress: %4⏎ Säilita vähemalt <n> ühendust peeridega (vaikeväärtus: 125) - + Connect to a node to retrieve peer addresses, and disconnect Peeri aadressi saamiseks ühendu korraks node'iga @@ -2262,22 +2257,22 @@ Aadress: %4⏎ Mitme sekundi pärast ulakad peerid tagasi võivad tulla (vaikeväärtus: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s RPC pordi %u kuulamiseks seadistamisel ilmnes viga IPv4'l: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Kuula JSON-RPC ühendusel seda porti <port> (vaikeväärtus: 8332 või testnet: 18332) - + Accept command line and JSON-RPC commands Luba käsurea ning JSON-RPC käsklusi - + Run in the background as a daemon and accept commands Tööta taustal ning aktsepteeri käsklusi @@ -2287,12 +2282,12 @@ Aadress: %4⏎ Testvõrgu kasutamine - + Accept connections from outside (default: 1 if no -proxy or -connect) Luba välisühendusi (vaikeväärtus: 1 kui puudub -proxy või -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2331,11 +2326,6 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Ei suuda määrata ainuõigust andmekaustale %s. Tõenäolisel on Bitcoin juba avatud. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Tõrge andmebaasi keskkonna käivitamisel %s! Taastumiseks VARUNDA SEE KAUST, seejärel kustuta kogu sisu peale wallet.dat faili. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2362,12 +2352,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Sea "kõrge tähtsusega"/"madala tehingu lisatasuga" tehingute maksimumsuurus baitides (vaikeväärtus: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Määra skripti kontrolli tegumite arv (1-16, 0=auto, vaikeväärtus: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications See on test-versioon - kasutamine omal riisikol - ära kasuta mining'uks ega kaupmeeste programmides @@ -2407,7 +2392,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Blokeeri loomise valikud: - + Connect only to the specified node(s) Ühendu ainult määratud node'i(de)ga @@ -2427,7 +2412,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Kas soovid bloki andmebaasi taastada? - + Error initializing block database Tõrge bloki andmebaasi käivitamisel @@ -2527,7 +2512,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Otsi DNS'i lookup'i kastavaid peere (vaikeväärtus: 1, kui mitte -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Käivitamisel kontrollitavate blokkide arv (vaikeväärtus: 288, 0=kõik) @@ -2537,7 +2527,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Blokkide kontrollimise põhjalikkus (0-4, vaikeväärtus: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Taasta bloki jada indeks blk000??.dat failist @@ -2557,12 +2552,17 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Kontrollin rahakotti... - + Imports blocks from external blk000??.dat file Impordi blokid välisest blk000??.dat failist - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Informatsioon @@ -2587,7 +2587,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Maksimaalne saatmise puhver -connection kohta , <n>*1000 baiti (vaikeväärtus: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Tunnusta ainult sisseehitatud turvapunktidele vastavaid bloki jadu (vaikeväärtus: 1) @@ -2702,12 +2702,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com JSON-RPC ühenduste salasõna - + Allow JSON-RPC connections from specified IP address JSON-RPC ühenduste lubamine kindla IP pealt - + Send commands to node running on <ip> (default: 127.0.0.1) Saada käsklusi node'ile IP'ga <ip> (vaikeväärtus: 127.0.0.1) @@ -2747,12 +2747,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Serveri privaatvõti (vaikeväärtus: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Lubatud šiffrid (vaikeväärtus: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Käesolev abitekst @@ -2767,12 +2767,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Ühendu läbi turva proxi - + Allow DNS lookups for -addnode, -seednode and -connect -addnode, -seednode ja -connect tohivad kasutada DNS lookup'i - + Loading addresses... Aadresside laadimine... @@ -2787,12 +2787,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Viga wallet.dat käivitamisel: Rahakott nõuab Bitcoini uusimat versiooni - + Wallet needed to be rewritten: restart Bitcoin to complete Rahakott tuli ümberkirjutada: toimingu lõpetamiseks taaskäivita Bitcoin - + Error loading wallet.dat Viga wallet.dat käivitamisel @@ -2802,7 +2802,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Vigane -proxi aadress: '%s' - + Unknown network specified in -onlynet: '%s' Kirjeldatud tundmatu võrgustik -onlynet'is: '%s' @@ -2822,7 +2822,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Tundmatu -externalip aadress: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<amount> jaoks vigane kogus: '%s' @@ -2842,7 +2842,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Klotside indeksi laadimine... - + Add a node to connect to and attempt to keep the connection open Lisa node ning hoia ühendus avatud @@ -2852,7 +2852,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com %s'ga ei ole võimalik sellest arvutist siduda. Bitcoin juba töötab. - + Fee per KB to add to transactions you send Minu saadetavate tehingute lisatasu KB kohta @@ -2862,15 +2862,10 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Rahakoti laadimine... - + Cannot downgrade wallet Rahakoti vanandamine ebaõnnestus - - - Cannot initialize keypool - Tõrge võtmehulga algatamisel - Cannot write default address @@ -2882,22 +2877,22 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Üleskaneerimine... - + Done loading Laetud - + To use the %s option %s valiku kasutamine - + Error Tõrge - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index 19cc33362..bfc228b87 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... Sarearekin sinkronizatzen... - + &Overview &Gainbegiratu @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network Konexio aktibo %n Bitcoin-en sarera%n konexio aktibo Bitcoin-en sarera @@ -661,7 +661,7 @@ Address: %4 Zorroa <b>enkriptatuta</b> eta <b>blokeatuta</b> dago une honetan - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version Botcoin bertsioa - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands Komandoen lista @@ -2189,7 +2194,7 @@ Address: %4 Laguntza komando batean - + Options: Aukerak @@ -2204,17 +2209,7 @@ Address: %4 pid fitxategia aukeratu (berezkoa: bitcoind.pid) - - Generate coins - &Jaso txanponak - - - - Don't generate coins - Ez jaso txanponik - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Laguntza mezu hau @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Birbilatzen... - + Done loading Zamaketa amaitua - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 1439eeda8..210f607c1 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -319,17 +319,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... امضا و پیام - + Synchronizing with network... همگام سازی با شبکه ... - + &Overview بررسی اجمالی @@ -404,7 +404,7 @@ This product includes software developed by the OpenSSL Project for use in the O تغییر Passphrase - + Importing blocks from disk... @@ -414,7 +414,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address سکه ها را به آدرس bitocin ارسال کن @@ -449,18 +449,18 @@ This product includes software developed by the OpenSSL Project for use in the O بازبینی پیام - - + + Bitcoin یت کویین - + Wallet wallet - + &Send @@ -536,7 +536,7 @@ This product includes software developed by the OpenSSL Project for use in the O مشتری Bitcoin - + %n active connection(s) to Bitcoin network در صد ارتباطات فعال بیتکویین با شبکه %n @@ -665,7 +665,7 @@ Address: %4 زمایش شبکه - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. خطا روی داده است. Bitcoin نمی تواند بدون مشکل ادامه دهد و باید بسته شود @@ -804,8 +804,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - نرخ اختیاری تراکنش هر کیلوبایت که به شما کمک می‌کند اطمینان پیدا کنید که تراکنش‌ها به سرعت پردازش می‌شوند. بیشتر تراکنش‌ها ۱ کیلوبایت هستند. نرخ 0.01 پیشنهاد می‌شود. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2133,12 +2133,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file داده ها نوارِ جاری را به فایل انتقال دهید - + Backup Wallet @@ -2171,12 +2176,12 @@ Address: %4 bitcoin-core - + Bitcoin version سخه بیتکویین - + Usage: ستفاده : @@ -2186,7 +2191,7 @@ Address: %4 ارسال فرمان به سرور یا باتکویین - + List commands لیست فومان ها @@ -2196,7 +2201,7 @@ Address: %4 کمک برای فرمان - + Options: تنظیمات @@ -2211,17 +2216,7 @@ Address: %4 (bitcoind.pidپیش فرض : ) فایل پید خاص - - Generate coins - سکه های تولید شده - - - - Don't generate coins - تولید سکه ها - - - + Specify data directory دایرکتور اطلاعاتی خاص @@ -2231,7 +2226,7 @@ Address: %4 سایز کَش بانک داده را بر حسب مگابایت تنظیم کنید (پیش فرض:25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) برای اتصالات به <port> (پیش‌فرض: 8333 یا تست‌نت: 18333) گوش کنید @@ -2241,7 +2236,7 @@ Address: %4 حداکثر <n> اتصال با همکاران برقرار داشته باشید (پیش‌فرض: 125) - + Connect to a node to retrieve peer addresses, and disconnect اتصال به گره برای دریافت آدرسهای قرینه و قطع اتصال @@ -2261,22 +2256,22 @@ Address: %4 مدت زمان به ثانیه برای جلوگیری از همکاران بدرفتار برای اتصال دوباره (پیش‌فرض: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s در زمان تنظیم درگاه RPX %u در فهرست کردن %s اشکالی رخ داده است - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) ( 8332پیش فرض :) &lt;poort&gt; JSON-RPC شنوایی برای ارتباطات - + Accept command line and JSON-RPC commands JSON-RPC قابل فرمانها و - + Run in the background as a daemon and accept commands اجرای در پس زمینه به عنوان شبح و قبول فرمان ها @@ -2286,12 +2281,12 @@ Address: %4 استفاده شبکه آزمایش - + Accept connections from outside (default: 1 if no -proxy or -connect) پذیرش اتصالات از بیرون (پیش فرض:1 بدون پراکسی یا اتصال) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2320,11 +2315,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2351,12 +2341,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. حجم حداکثر تراکنشهای با/کم اهمیت را به بایت تنظیم کنید (پیش فرض:27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2396,7 +2381,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. بستن گزینه ایجاد - + Connect only to the specified node(s) تنها در گره (های) مشخص شده متصل شوید @@ -2416,7 +2401,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2516,7 +2501,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. قرینه ها را برای جستجوی DNS بیاب (پیش فرض: 1 مگر در زمان اتصال) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2526,7 +2516,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2546,12 +2541,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2576,7 +2576,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. حداکثر بافر دریافت شده بر اساس اتصال <n>* 1000 بایت (پیش فرض:1000) - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2691,12 +2691,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. JSON-RPC عبارت عبور برای ارتباطات - + Allow JSON-RPC connections from specified IP address از آدرس آی پی خاص JSON-RPC قبول ارتباطات - + Send commands to node running on <ip> (default: 127.0.0.1) (127.0.0.1پیش فرض: ) &lt;ip&gt; دادن فرمانها برای استفاده گره ها روی @@ -2736,12 +2736,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. (server.pemپیش فرض: ) کلید خصوصی سرور - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) رمز های قابل قبول( TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message پیام کمکی @@ -2756,12 +2756,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. اتصال از طریق پراکسی ساکس - + Allow DNS lookups for -addnode, -seednode and -connect به DNS اجازه بده تا برای addnode ، seednode و اتصال جستجو کند - + Loading addresses... بار گیری آدرس ها @@ -2776,12 +2776,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. خطا در بارگیری wallet.dat: کیف پول به ویرایش جدیدتری از Biticon نیاز دارد - + Wallet needed to be rewritten: restart Bitcoin to complete سلام - + Error loading wallet.dat خطا در بارگیری wallet.dat @@ -2791,7 +2791,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. آدرس پراکسی اشتباه %s - + Unknown network specified in -onlynet: '%s' شبکه مشخص شده غیرقابل شناسایی در onlynet: '%s' @@ -2811,7 +2811,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. آدرس خارجی قابل اتصال- شناسایی نیست %s - + Invalid amount for -paytxfee=<amount>: '%s' میزان وجه اشتباه برای paytxfee=<میزان وجه>: %s @@ -2831,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. بار گیری شاخص بلوک - + Add a node to connect to and attempt to keep the connection open به اتصال یک گره اضافه کنید و اتصال را باز نگاه دارید @@ -2841,7 +2841,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. اتصال به %s از این رایانه امکان پذیر نیست. Bitcoin احتمالا در حال اجراست. - + Fee per KB to add to transactions you send پر داجت برای هر کیلو بیت برای اضافه به معامله ارسال @@ -2851,15 +2851,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. بار گیری والت - + Cannot downgrade wallet امکان تنزل نسخه در wallet وجود ندارد - - - Cannot initialize keypool - امکان مقداردهی اولیه برای key pool وجود ندارد - Cannot write default address @@ -2871,22 +2866,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. اسکان مجدد - + Done loading بار گیری انجام شده است - + To use the %s option برای استفاده از %s از انتخابات - + Error خطا - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index f53b6e054..f1ec3587c 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... امضا و پیام - + Synchronizing with network... به روز رسانی با شبکه... - + &Overview و بازبینی @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O تغییر رمز/پَس فرِیز - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin bitcoin - + Wallet کیف پول - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O مشتری bitcoin - + %n active connection(s) to Bitcoin network %n ارتباط فعال به شبکه Bitcoin %n ارتباط فعال به شبکه Bitcoin @@ -663,7 +663,7 @@ Address: %4 wallet رمزگذاری شد و در حال حاضر قفل است - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -802,7 +802,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2129,12 +2129,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file صدور داده نوار جاری به یک فایل - + Backup Wallet @@ -2167,12 +2172,12 @@ Address: %4 bitcoin-core - + Bitcoin version نسخه bitcoin - + Usage: میزان استفاده: @@ -2182,7 +2187,7 @@ Address: %4 ارسال دستور به سرور یا bitcoined - + List commands فهرست دستورها @@ -2192,7 +2197,7 @@ Address: %4 درخواست کمک برای یک دستور - + Options: انتخابها: @@ -2207,17 +2212,7 @@ Address: %4 فایل pid را مشخص کنید (پیش فرض: bitcoind.pid) - - Generate coins - سکه ها را تولید کن - - - - Don't generate coins - سکه ها را تولید نکن - - - + Specify data directory دایرکتوری داده را مشخص کن @@ -2227,7 +2222,7 @@ Address: %4 حافظه بانک داده را به مگابایت تنظیم کنید (پیش فرض: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) ارتباطات را در <PORT> بشنوید (پیش فرض: 8333 or testnet: 18333) @@ -2237,7 +2232,7 @@ Address: %4 نگهداری <N> ارتباطات برای قرینه سازی (پیش فرض:125) - + Connect to a node to retrieve peer addresses, and disconnect @@ -2257,22 +2252,22 @@ Address: %4 تعداد ثانیه ها برای اتصال دوباره قرینه های اشتباه (پیش فرض:86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) ارتباطاتِ JSON-RPC را در <port> گوش کنید (پیش فرض:8332) - + Accept command line and JSON-RPC commands command line و JSON-RPC commands را قبول کنید - + Run in the background as a daemon and accept commands به عنوان daemon بک گراند را اجرا کنید و دستورات را قبول نمایید @@ -2282,12 +2277,12 @@ Address: %4 از تستِ شبکه استفاده نمایید - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2316,11 +2311,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2347,12 +2337,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2392,7 +2377,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2412,7 +2397,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2512,7 +2497,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2522,7 +2512,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2542,12 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2572,7 +2572,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2687,12 +2687,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. رمز برای ارتباطاتِ JSON-RPC - + Allow JSON-RPC connections from specified IP address ارتباطاتِ JSON-RPC را از آدرس آی.پی. مشخصی برقرار کنید. - + Send commands to node running on <ip> (default: 127.0.0.1) دستورات را به گره اجرا شده در<ip> ارسال کنید (پیش فرض:127.0.0.1) @@ -2732,12 +2732,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. رمز اختصاصی سرور (پیش فرض: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) ciphers قابل قبول (پیش فرض: default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message این پیام راهنما @@ -2752,12 +2752,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... لود شدن آدرسها.. @@ -2772,12 +2772,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. خطا در هنگام لود شدن wallet.dat. به نسخه جدید Bitocin برای wallet نیاز است. - + Wallet needed to be rewritten: restart Bitcoin to complete wallet نیاز به بازنویسی دارد. Bitcoin را برای تکمیل عملیات دوباره اجرا کنید. - + Error loading wallet.dat خطا در هنگام لود شدن wallet.dat @@ -2787,7 +2787,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2807,7 +2807,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' میزان اشتباه است for -paytxfee=<amount>: '%s' @@ -2827,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. لود شدن نمایه بلاکها.. - + Add a node to connect to and attempt to keep the connection open یک گره برای اتصال اضافه کنید و تلاش کنید تا اتصال را باز نگاه دارید @@ -2837,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send هزینه بر اساس کیلو بایت برای اضافه شدن به تراکنشی که ارسال کرده اید @@ -2847,15 +2847,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet در حال لود شدن است... - + Cannot downgrade wallet قابلیت برگشت به نسخه قبلی برای wallet امکان پذیر نیست - - - Cannot initialize keypool - initialize keypool امکان پذیر نیست - Cannot write default address @@ -2867,22 +2862,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. اسکنِ دوباره... - + Done loading اتمام لود شدن - + To use the %s option برای استفاده از %s از اختیارات - + Error خطا - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index d38c21e8d..70803e7f6 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -324,17 +324,17 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o BitcoinGUI - + Sign &message... &Allekirjoita viesti... - + Synchronizing with network... Synkronoidaan verkon kanssa... - + &Overview &Yleisnäkymä @@ -409,7 +409,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o &Vaihda Tunnuslause... - + Importing blocks from disk... Tuodaan lohkoja levyltä @@ -419,7 +419,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Ladataan lohkoindeksiä... - + Send coins to a Bitcoin address Lähetä kolikoita Bitcoin-osoitteeseen @@ -454,18 +454,18 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Varmista &viesti... - - + + Bitcoin Bitcoin - + Wallet Lompakko - + &Send &Lähetä @@ -541,7 +541,7 @@ Tämä ohjelma sisältää OpenSSL projektin OpenSSL työkalupakin (http://www.o Bitcoin-asiakas - + %n active connection(s) to Bitcoin network %n aktiivinen yhteys Bitcoin-verkkoon%n aktiivista yhteyttä Bitcoin-verkkoon @@ -670,7 +670,7 @@ Osoite: %4 Lompakko on <b>salattu</b> ja tällä hetkellä <b>lukittuna</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Peruuttamaton virhe on tapahtunut. Bitcoin ei voi enää jatkaa turvallisesti ja sammutetaan. @@ -809,8 +809,8 @@ Osoite: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Vapaaehtoinen rahansiirtopalkkio per kB auttaa nopeuttamaan siirtoja. Useimmat rahansiirrot ovat 1 kB. 0.01 palkkio on suositeltava. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2135,12 +2135,17 @@ Osoite: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Vie auki olevan välilehden tiedot tiedostoon - + Backup Wallet @@ -2173,12 +2178,12 @@ Osoite: %4 bitcoin-core - + Bitcoin version Bitcoinin versio - + Usage: Käyttö: @@ -2188,7 +2193,7 @@ Osoite: %4 Lähetä käsky palvelimelle tai bitcoind:lle - + List commands Lista komennoista @@ -2198,7 +2203,7 @@ Osoite: %4 Hanki apua käskyyn - + Options: Asetukset: @@ -2213,17 +2218,7 @@ Osoite: %4 Määritä pid-tiedosto (oletus: bitcoin.pid) - - Generate coins - Generoi kolikoita - - - - Don't generate coins - Älä generoi kolikoita - - - + Specify data directory Määritä data-hakemisto @@ -2233,7 +2228,7 @@ Osoite: %4 Aseta tietokannan välimuistin koko megatavuina (oletus: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Kuuntele yhteyksiä portista <port> (oletus: 8333 tai testnet: 18333) @@ -2243,7 +2238,7 @@ Osoite: %4 Pidä enintään <n> yhteyttä verkkoihin (oletus: 125) - + Connect to a node to retrieve peer addresses, and disconnect Yhdistä noodiin hakeaksesi naapurien osoitteet ja katkaise yhteys @@ -2263,22 +2258,22 @@ Osoite: %4 Sekuntien määrä, kuinka kauan uudelleenkytkeydytään verkkoihin (oletus: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Virhe valmisteltaessa RPC-portin %u avaamista kuunneltavaksi: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Kuuntele JSON-RPC -yhteyksiä portista <port> (oletus: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Hyväksy merkkipohjaiset- ja JSON-RPC-käskyt - + Run in the background as a daemon and accept commands Aja taustalla daemonina ja hyväksy komennot @@ -2288,12 +2283,12 @@ Osoite: %4 Käytä test -verkkoa - + Accept connections from outside (default: 1 if no -proxy or -connect) Hyväksy yhteyksiä ulkopuolelta (vakioasetus: 1 jos -proxy tai -connect ei määritelty) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2322,11 +2317,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2353,12 +2343,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Aseta suurin korkean prioriteetin / matalan palkkion siirron koko tavuissa (vakioasetus: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2398,7 +2383,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Lohkon luonnin asetukset: - + Connect only to the specified node(s) Yhidstä ainoastaan määrättyihin noodeihin @@ -2418,7 +2403,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2518,7 +2503,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Hae naapureita DNS hauilla (vakioasetus: 1 paitsi jos -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2528,7 +2518,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2548,12 +2543,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file Tuodaan lohkoja ulkoisesta blk000??.dat tiedostosta - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Tietoa @@ -2578,7 +2578,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Suurin lähetyspuskuri yksittäiselle yhteydelle, <n>*1000 tavua (vakioasetus: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2693,12 +2693,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Salasana JSON-RPC-yhteyksille - + Allow JSON-RPC connections from specified IP address Salli JSON-RPC yhteydet tietystä ip-osoitteesta - + Send commands to node running on <ip> (default: 127.0.0.1) Lähetä käskyjä solmuun osoitteessa <ip> (oletus: 127.0.0.1) @@ -2738,13 +2738,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Palvelimen yksityisavain (oletus: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Hyväksyttävä salaus (oletus: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Tämä ohjeviesti @@ -2759,12 +2759,12 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Yhdistä socks proxyn läpi - + Allow DNS lookups for -addnode, -seednode and -connect Salli DNS kyselyt -addnode, -seednode ja -connect yhteydessä - + Loading addresses... Ladataan osoitteita... @@ -2779,12 +2779,12 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Virhe ladattaessa wallet.dat-tiedostoa: Tarvitset uudemman version Bitcoinista - + Wallet needed to be rewritten: restart Bitcoin to complete Lompakko tarvitsee uudelleenkirjoittaa: käynnistä Bitcoin uudelleen - + Error loading wallet.dat Virhe ladattaessa wallet.dat-tiedostoa @@ -2794,7 +2794,7 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Virheellinen proxy-osoite '%s' - + Unknown network specified in -onlynet: '%s' Tuntematon verkko -onlynet parametrina: '%s' @@ -2814,7 +2814,7 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) -externalip osoitteen '%s' selvittäminen epäonnistui - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<amount>: '%s' on virheellinen @@ -2834,7 +2834,7 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Ladataan lohkoindeksiä... - + Add a node to connect to and attempt to keep the connection open Linää solmu mihin liittyä pitääksesi yhteyden auki @@ -2844,7 +2844,7 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Kytkeytyminen %s ei onnistu tällä tietokoneella. Bitcoin on todennäköisesti jo ajamassa. - + Fee per KB to add to transactions you send Rahansiirtopalkkio per KB lisätään lähettämääsi rahansiirtoon @@ -2854,15 +2854,10 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Ladataan lompakkoa... - + Cannot downgrade wallet Et voi päivittää lompakkoasi vanhempaan versioon - - - Cannot initialize keypool - Avainvarastoa ei voi alustaa - Cannot write default address @@ -2874,22 +2869,22 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Skannataan uudelleen... - + Done loading Lataus on valmis - + To use the %s option Käytä %s optiota - + Error Virhe - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index d0113ff27..33027d3f3 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Signer un &message... - + Synchronizing with network... Synchronisation avec le réseau… - + &Overview &Vue d'ensemble @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Modifier la phrase de passe... - + Importing blocks from disk... Importation des blocs depuis le disque... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Réindexation des blocs sur le disque... - + Send coins to a Bitcoin address Envoyer des pièces à une adresse Bitcoin @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Vérifier un message... - - + + Bitcoin Bitcoin - + Wallet Porte-monnaie - + &Send &Envoyer @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O Client Bitcoin - + %n active connection(s) to Bitcoin network %n connexion active avec le réseau Bitcoin%n connexions actives avec le réseau Bitcoin @@ -670,7 +670,7 @@ Adresse : %4 Le porte-monnaie est <b>chiffré</b> et est actuellement <b>verrouillé</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Une erreur fatale est survenue. Bitcoin ne peut plus continuer à fonctionner de façon sûre et va s'arrêter. @@ -809,8 +809,8 @@ Adresse : %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Frais de transaction optionnels par ko qui aident à garantir un traitement rapide des transactions. La plupart des transactions occupent 1 ko. Des frais de 0.01 sont recommandés. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Frais de transaction optionnel par ko qui aident à garantir un traitement rapide des transactions. La plupart des transactions utilisent 1 ko. @@ -2135,12 +2135,17 @@ Adresse : %4 WalletView - + + &Export + &Exporter + + + Export the data in the current tab to a file Exporter les données de l'onglet courant vers un fichier - + Backup Wallet Sauvegarder le porte-monnaie @@ -2173,12 +2178,12 @@ Adresse : %4 bitcoin-core - + Bitcoin version Version de Bitcoin - + Usage: Utilisation : @@ -2188,7 +2193,7 @@ Adresse : %4 Envoyer une commande à -server ou à bitcoind - + List commands Lister les commandes @@ -2198,7 +2203,7 @@ Adresse : %4 Obtenir de l’aide pour une commande - + Options: Options : @@ -2213,17 +2218,7 @@ Adresse : %4 Spécifier le fichier PID (par défaut : bitcoind.pid) - - Generate coins - Générer des pièces - - - - Don't generate coins - Ne pas générer de pièces - - - + Specify data directory Spécifier le répertoire de données @@ -2233,7 +2228,7 @@ Adresse : %4 Définir la taille du tampon en mégaoctets (par défaut : 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Écouter les connexions sur le <port> (par défaut : 8333 ou testnet : 18333) @@ -2243,7 +2238,7 @@ Adresse : %4 Garder au plus <n> connexions avec les pairs (par défaut : 125) - + Connect to a node to retrieve peer addresses, and disconnect Se connecter à un nœud pour obtenir des adresses de pairs puis se déconnecter @@ -2263,22 +2258,22 @@ Adresse : %4 Délai en secondes de refus de reconnexion aux pairs de mauvaise qualité (par défaut : 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Une erreur est survenue lors de la mise en place du port RPC %u pour écouter sur IPv4 : %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Écouter les connexions JSON-RPC sur le <port> (par défaut : 8332 ou tesnet : 18332) - + Accept command line and JSON-RPC commands Accepter les commandes de JSON-RPC et de la ligne de commande - + Run in the background as a daemon and accept commands Fonctionner en arrière-plan en tant que démon et accepter les commandes @@ -2288,12 +2283,12 @@ Adresse : %4 Utiliser le réseau de test - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepter les connexions entrantes (par défaut : 1 si -proxy ou -connect ne sont pas présents) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2332,11 +2327,6 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Impossible d’obtenir un verrou sur le répertoire de données %s. Bitcoin fonctionne probablement déjà. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Une erreur est survenue lors de l'initialisation de l'environnement de base de données %s ! Pour récupérer, SAUVEGARDEZ CE RÉPERTOIRE, puis effacez-y tous les fichiers à l'exception de wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2363,12 +2353,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Définir la taille maximale en octets des transactions prioritaires/à frais modiques (par défaut : 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Définir le nombre de fils de vérification de script (1-16, 0=auto, par défaut : 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Ceci est une pré-version de test - utilisez à vos risques et périls - ne l'utilisez pas pour miner ou pour des applications marchandes @@ -2408,7 +2393,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Options de création des blocs : - + Connect only to the specified node(s) Ne se connecter qu'au(x) nœud(s) spécifié(s) @@ -2428,7 +2413,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Voulez-vous reconstruire la base de données des blocs maintenant ? - + Error initializing block database Erreur lors de l'initialisation de la base de données des blocs @@ -2528,7 +2513,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Trouver des pairs en utilisant la recherche DNS (par défaut : 1 sauf si -connect est utilisé) - + + Generate coins (default: 0) + Générer des pièces (défaut: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Nombre de blocs à vérifier au démarrage (par défaut : 288, 0 = tout) @@ -2538,7 +2528,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Niveau d'approfondissement de la vérification des blocs (0-4, par défaut : 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Reconstruire l'index de la chaîne des blocs à partir des fichiers blk000??.dat actuels @@ -2558,12 +2553,17 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Vérification du porte-monnaie... - + Imports blocks from external blk000??.dat file Importe des blocs depuis un fichier blk000??.dat externe - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Informations @@ -2588,7 +2588,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Tampon maximal d'envoi par connexion, <n>*1000 octets (par défaut : 1000) - + Only accept block chain matching built-in checkpoints (default: 1) N'accepter que la chaîne de blocs correspondant aux points de vérification internes (par défaut : 1) @@ -2703,12 +2703,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Mot de passe pour les connexions JSON-RPC - + Allow JSON-RPC connections from specified IP address Autoriser les connexions JSON-RPC depuis l'adresse IP spécifiée - + Send commands to node running on <ip> (default: 127.0.0.1) Envoyer des commandes au nœud fonctionnant à <ip> (par défaut : 127.0.0.1) @@ -2748,12 +2748,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Clef privée du serveur (par défaut : server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Clefs de chiffrement acceptables (par défaut : TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ce message d'aide @@ -2768,12 +2768,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Connexion via un proxy socks - + Allow DNS lookups for -addnode, -seednode and -connect Autoriser les recherches DNS pour -addnode, -seednode et -connect - + Loading addresses... Chargement des adresses… @@ -2788,12 +2788,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Erreur lors du chargement de wallet.dat : le porte-monnaie nécessite une version plus récente de Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Le porte-monnaie nécessitait une réécriture : veuillez redémarrer Bitcoin pour terminer l'opération - + Error loading wallet.dat Erreur lors du chargement de wallet.dat @@ -2803,7 +2803,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Adresse -proxy invalide : « %s » - + Unknown network specified in -onlynet: '%s' Réseau inconnu spécifié sur -onlynet : « %s » @@ -2823,7 +2823,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Impossible de résoudre l'adresse -externalip : « %s » - + Invalid amount for -paytxfee=<amount>: '%s' Montant invalide pour -paytxfee=<montant> : « %s » @@ -2843,7 +2843,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Chargement de l’index des blocs… - + Add a node to connect to and attempt to keep the connection open Ajouter un nœud auquel se connecter et tenter de garder la connexion ouverte @@ -2853,7 +2853,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Impossible de se lier à %s sur cet ordinateur. Bitcoin fonctionne probablement déjà. - + Fee per KB to add to transactions you send Frais par Ko à ajouter aux transactions que vous enverrez @@ -2863,15 +2863,10 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Chargement du porte-monnaie… - + Cannot downgrade wallet Impossible de revenir à une version antérieure du porte-monnaie - - - Cannot initialize keypool - Impossible d'initialiser la plage des clefs - Cannot write default address @@ -2883,22 +2878,22 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Nouvelle analyse… - + Done loading Chargement terminé - + To use the %s option Pour utiliser l'option %s - + Error Erreur - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index 9ad663b57..1dddf75bf 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -323,17 +323,17 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -408,7 +408,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + Importing blocks from disk... @@ -418,7 +418,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + Send coins to a Bitcoin address @@ -453,18 +453,18 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - - + + Bitcoin - + Wallet - + &Send @@ -540,7 +540,7 @@ Ce produit comprend des logiciels développés par le projet OpenSSL pour être - + %n active connection(s) to Bitcoin network @@ -666,7 +666,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -805,7 +805,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2131,12 +2131,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2169,12 +2174,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2184,7 +2189,7 @@ Address: %4 - + List commands @@ -2194,7 +2199,7 @@ Address: %4 - + Options: @@ -2209,17 +2214,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2229,7 +2224,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2239,7 +2234,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2259,22 +2254,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2284,12 +2279,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2318,11 +2313,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2349,12 +2339,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2394,7 +2379,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2414,7 +2399,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2514,7 +2499,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2524,7 +2514,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2544,12 +2539,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2574,7 +2574,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2689,12 +2689,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2734,12 +2734,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2754,12 +2754,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2774,12 +2774,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2789,7 +2789,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2809,7 +2809,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2829,7 +2829,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2839,7 +2839,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2849,15 +2849,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2869,22 +2864,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts index c052af5b1..2b930a4aa 100644 --- a/src/qt/locale/bitcoin_gu_IN.ts +++ b/src/qt/locale/bitcoin_gu_IN.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 63a03bc84..499daf100 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... חתום על הודעה - + Synchronizing with network... מסתנכרן עם הרשת... - + &Overview &סקירה @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O שנה סיסמא - + Importing blocks from disk... מייבא בלוקים מהדיסק... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O מחדש את אינדקס הבלוקים בדיסק... - + Send coins to a Bitcoin address שלח מטבעות לכתובת ביטקוין @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O אמת הודעה... - - + + Bitcoin ביטקוין - + Wallet ארנק - + &Send ושלח @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O תוכנת ביטקוין - + %n active connection(s) to Bitcoin network חיבור פעיל אחד לרשת הביטקוין%n חיבורים פעילים לרשת הביטקוין @@ -669,7 +669,7 @@ Address: %4 הארנק <b>מוצפן</b> וכרגע <b>נעול</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. שגיאה סופנית אירעה. ביטקוין אינו יכול להמשיך לפעול בבטחה ולכן ייסגר. @@ -808,8 +808,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - עמלת פעולה אופציונלית לכל kB תבטיח שהפעולה שלך תעובד בזריזות. רוב הפעולות הן 1 kB. מומלצת עמלה בסך 0.01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2134,12 +2134,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file יצוא הנתונים בטאב הנוכחי לקובץ - + Backup Wallet גבה ארנק @@ -2172,12 +2177,12 @@ Address: %4 bitcoin-core - + Bitcoin version גרסת ביטקוין - + Usage: שימוש: @@ -2187,7 +2192,7 @@ Address: %4 שלח פקודה ל -server או bitcoind - + List commands רשימת פקודות @@ -2197,7 +2202,7 @@ Address: %4 קבל עזרה עבור פקודה - + Options: אפשרויות: @@ -2212,17 +2217,7 @@ Address: %4 ציין קובץ pid (ברירת מחדל: bitcoind.pid) - - Generate coins - צור מטבעות - - - - Don't generate coins - אל תייצר מטבעות - - - + Specify data directory ציין תיקיית נתונים @@ -2232,7 +2227,7 @@ Address: %4 קבע את גודל המטמון של מסד הנתונים במגהבייט (ברירת מחדל: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) האזן לחיבורים ב<פורט> (ברירת מחדל: 8333 או ברשת הבדיקה: 18333) @@ -2242,7 +2237,7 @@ Address: %4 החזק לכל היותר <n> חיבורים לעמיתים (ברירת מחדל: 125) - + Connect to a node to retrieve peer addresses, and disconnect התחבר לצומת כדי לדלות כתובות עמיתים, ואז התנתק @@ -2262,22 +2257,22 @@ Address: %4 מספר שניות למנוע מעמיתים הנוהגים שלא כהלכה מלהתחבר מחדש (ברירת מחדל: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s אירעה שגיאה בעת הגדרת פורט RPC %u להאזנה ב-IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) האזן לחיבורי JSON-RPC ב- <port> (ברירת מחדל: 8332 או רשת בדיקה: 18332) - + Accept command line and JSON-RPC commands קבל פקודות משורת הפקודה ו- JSON-RPC - + Run in the background as a daemon and accept commands רוץ ברקע כדימון וקבל פקודות @@ -2287,12 +2282,12 @@ Address: %4 השתמש ברשת הבדיקה - + Accept connections from outside (default: 1 if no -proxy or -connect) קבל חיבורים מבחוץ (ברירת מחדל: 1 ללא -proxy או -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2331,11 +2326,6 @@ rpcpassword=%s Cannot obtain a lock on data directory %s. Bitcoin is probably already running. לא מסוגל להשיג נעילה על תיקיית הנתונים %s. כנראה שביטקוין כבר רץ. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - שגיאה באתחול סביבת מסד הנתונים %s! בשביל להתאושש, גבה את התיקיה הזאת, ואז הסר הכל מלבד wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2362,12 +2352,7 @@ rpcpassword=%s קבע גודל מקסימלי עבור פעולות עדיפות גבוהה/עמלה נמוכה בבתים (ברירת מחדל: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - קבע את מספר תהליכוני אימות הסקריפטים (1-16, 0 = אוטומטי, ברירת מחדל: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications זוהי בניית ניסיון טרום-שחרור - השימוש בה על אחריותך - אין להשתמש לצורך כריה או יישומי מסחר @@ -2407,7 +2392,7 @@ rpcpassword=%s אפשרויות יצירת בלוק: - + Connect only to the specified node(s) התחבר רק לצמתים המצוינים @@ -2427,7 +2412,7 @@ rpcpassword=%s האם תרצה כעט לבנות מחדש את מסד נתוני הבלוקים? - + Error initializing block database שגיאה באתחול מסד נתוני הבלוקים @@ -2527,7 +2512,12 @@ rpcpassword=%s מצא עמיתים ע"י חיפוש DNS (ברירת מחדל: 1 ללא -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) מספר הבלוקים לבדוק בעת אתחול (ברירת מחדל: 288, 0 = כולם) @@ -2537,7 +2527,12 @@ rpcpassword=%s מידת היסודיות של אימות הבלוקים (0-4, ברירת מחדל: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files בנה מחדש את אינדק שרשרת הבלוקים מקבצי ה-blk000??.dat הנוכחיים. @@ -2557,12 +2552,17 @@ rpcpassword=%s מאמת את יושרת הארנק... - + Imports blocks from external blk000??.dat file מייבא בלוקים מקובצי blk000??.dat חיצוניים - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information מידע @@ -2587,7 +2587,7 @@ rpcpassword=%s חוצץ שליחה מירבי לכל חיבור, <n>*1000 בתים (ברירת מחדל: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) קבל רק שרשרת בלוקים התואמת נקודות ביקורת מובנות (ברירת מחדל: 1) @@ -2702,12 +2702,12 @@ rpcpassword=%s סיסמה לחיבורי JSON-RPC - + Allow JSON-RPC connections from specified IP address אפשר חיבורי JSON-RPC מכתובת האינטרנט המצוינת - + Send commands to node running on <ip> (default: 127.0.0.1) שלח פקודות לצומת ב-<ip> (ברירת מחדל: 127.0.0.1) @@ -2747,12 +2747,12 @@ rpcpassword=%s מפתח פרטי של השרת (ברירת מחדל: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) צפנים קבילים (ברירת מחדל: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message הודעת העזרה הזו @@ -2767,12 +2767,12 @@ rpcpassword=%s התחבר דרך פרוקסי SOCKS - + Allow DNS lookups for -addnode, -seednode and -connect אפשר בדיקת DNS עבור -addnode, -seednode ו- -connect - + Loading addresses... טוען כתובות... @@ -2787,12 +2787,12 @@ rpcpassword=%s שגיאה בטעינת הקובץ wallet.dat: הארנק דורש גרסה חדשה יותר של ביטקוין - + Wallet needed to be rewritten: restart Bitcoin to complete יש לכתוב מחדש את הארנק: אתחל את ביטקוין לסיום - + Error loading wallet.dat שגיאה בטעינת הקובץ wallet.dat @@ -2802,7 +2802,7 @@ rpcpassword=%s כתובת -proxy לא תקינה: '%s' - + Unknown network specified in -onlynet: '%s' רשת לא ידועה צוינה ב- -onlynet: '%s' @@ -2822,7 +2822,7 @@ rpcpassword=%s לא מסוגל לפתור כתובת -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' כמות לא תקינה עבור -paytxfee=<amount>: '%s' @@ -2842,7 +2842,7 @@ rpcpassword=%s טוען את אינדקס הבלוקים... - + Add a node to connect to and attempt to keep the connection open הוסף צומת להתחברות ונסה לשמור את החיבור פתוח @@ -2852,7 +2852,7 @@ rpcpassword=%s לא ניתן לקשור ל-%s במחשב זה. ביטקוין כנראה עדיין רץ. - + Fee per KB to add to transactions you send עמלה להוסיף לפעולות שאתה שולח עבור כל KB @@ -2862,15 +2862,10 @@ rpcpassword=%s טוען ארנק... - + Cannot downgrade wallet לא יכול להוריד דרגת הארנק - - - Cannot initialize keypool - לא יכול לאתחל את מאגר המפתחות - Cannot write default address @@ -2882,22 +2877,22 @@ rpcpassword=%s סורק מחדש... - + Done loading טעינה הושלמה - + To use the %s option להשתמש באפשרות %s - + Error שגיאה - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index ecdb3405e..1c38925d0 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... नेटवर्क से समकालिक (मिल) रहा है ... - + &Overview &विवरण @@ -404,7 +404,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -414,7 +414,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -449,18 +449,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin बीटकोइन - + Wallet वॉलेट - + &Send @@ -536,7 +536,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network %n सक्रिया संपर्क बीटकोइन नेटवर्क से%n सक्रिया संपर्क बीटकोइन नेटवर्क से @@ -665,7 +665,7 @@ Address: %4 वॉलेट एन्क्रिप्टेड है तथा अभी लॉक्ड है - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -804,7 +804,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2131,12 +2131,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet बैकप वॉलेट @@ -2169,12 +2174,12 @@ Address: %4 bitcoin-core - + Bitcoin version बीटकोइन संस्करण - + Usage: खपत : @@ -2184,7 +2189,7 @@ Address: %4 -server या bitcoind को कमांड भेजें - + List commands commands की लिस्ट बनाएं @@ -2194,7 +2199,7 @@ Address: %4 किसी command के लिए मदद लें - + Options: विकल्प: @@ -2209,17 +2214,7 @@ Address: %4 pid फाइल का विवरण दें (default: bitcoin.pid) - - Generate coins - Coins बनाएं - - - - Don't generate coins - Coins न बनाएं - - - + Specify data directory @@ -2229,7 +2224,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2239,7 +2234,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2259,22 +2254,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2284,12 +2279,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2318,11 +2313,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2349,12 +2339,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2394,7 +2379,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2414,7 +2399,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2514,7 +2499,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2524,7 +2514,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2544,12 +2539,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. वॉलेट जाँचा जा रहा है... - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information जानकारी @@ -2574,7 +2574,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2689,12 +2689,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2734,12 +2734,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2754,12 +2754,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... पता पुस्तक आ रही है... @@ -2774,12 +2774,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2789,7 +2789,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2809,7 +2809,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2829,7 +2829,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. ब्लॉक इंडेक्स आ रहा है... - + Add a node to connect to and attempt to keep the connection open @@ -2839,7 +2839,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2849,15 +2849,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. वॉलेट आ रहा है... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2869,22 +2864,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. रि-स्केनी-इंग... - + Done loading लोड हो गया| - + To use the %s option - + Error भूल - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index fb26af366..ef8b2b759 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Potpišite poruku... - + Synchronizing with network... Usklađivanje s mrežom ... - + &Overview &Pregled @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Promijena lozinke... - + Importing blocks from disk... Importiranje blokova sa diska... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O Re-indeksiranje blokova na disku... - + Send coins to a Bitcoin address Slanje novca na bitcoin adresu @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin Bitcoin - + Wallet Novčanik - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin klijent - + %n active connection(s) to Bitcoin network %n aktivna veza na Bitcoin mrežu%n aktivne veze na Bitcoin mrežu%n aktivnih veza na Bitcoin mrežu @@ -665,7 +665,7 @@ Adresa:%4 Novčanik je <b>šifriran</b> i trenutno <b>zaključan</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -804,8 +804,8 @@ Adresa:%4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Neobavezna naknada za transakciju po kB koja omogućuje da se vaša transakcija obavi brže. Većina transakcija ima 1 kB. Preporučena naknada je 0.01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2130,12 +2130,17 @@ Adresa:%4 WalletView - + + &Export + + + + Export the data in the current tab to a file Izvoz podataka iz trenutnog taba u datoteku - + Backup Wallet @@ -2168,12 +2173,12 @@ Adresa:%4 bitcoin-core - + Bitcoin version Bitcoin verzija - + Usage: Upotreba: @@ -2183,7 +2188,7 @@ Adresa:%4 Pošalji komandu usluzi -server ili bitcoind - + List commands Prikaži komande @@ -2193,7 +2198,7 @@ Adresa:%4 Potraži pomoć za komandu - + Options: Postavke: @@ -2208,17 +2213,7 @@ Adresa:%4 Odredi proces ID datoteku (ugrađeni izbor: bitcoin.pid) - - Generate coins - Generiraj novčiće - - - - Don't generate coins - Ne generiraj novčiće - - - + Specify data directory Odredi direktorij za datoteke @@ -2228,7 +2223,7 @@ Adresa:%4 Postavi cache za bazu podataka u MB (zadano:25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Slušaj na <port>u (default: 8333 ili testnet: 18333) @@ -2238,7 +2233,7 @@ Adresa:%4 Održavaj najviše <n> veza sa članovima (default: 125) - + Connect to a node to retrieve peer addresses, and disconnect @@ -2258,22 +2253,22 @@ Adresa:%4 Broj sekundi koliko se članovima koji se čudno ponašaju neće dopustiti da se opet spoje (default: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Prihvaćaj JSON-RPC povezivanje na portu broj <port> (ugrađeni izbor: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Prihvati komande iz tekst moda i JSON-RPC - + Run in the background as a daemon and accept commands Izvršavaj u pozadini kao uslužnik i prihvaćaj komande @@ -2283,12 +2278,12 @@ Adresa:%4 Koristi test mrežu - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2317,11 +2312,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2348,12 +2338,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2393,7 +2378,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Opcije za kreiranje bloka: - + Connect only to the specified node(s) Poveži se samo sa određenim nodom @@ -2413,7 +2398,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2513,7 +2498,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2523,7 +2513,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2543,12 +2538,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file Importiraj blokove sa vanjskog blk000??.dat fajla - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2573,7 +2573,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) Prihvati samo lance blokova koji se podudaraju sa ugrađenim checkpoint-ovima (default: 1) @@ -2688,12 +2688,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Lozinka za JSON-RPC veze - + Allow JSON-RPC connections from specified IP address Dozvoli JSON-RPC povezivanje s određene IP adrese - + Send commands to node running on <ip> (default: 127.0.0.1) Pošalji komande nodu na adresi <ip> (ugrađeni izbor: 127.0.0.1) @@ -2733,12 +2733,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Uslužnikov privatni ključ (ugrađeni izbor: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Prihvaljivi načini šifriranja (ugrađeni izbor: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ova poruka za pomoć @@ -2753,12 +2753,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Poveži se kroz socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Dozvoli DNS upite za dodavanje nodova i povezivanje - + Loading addresses... Učitavanje adresa... @@ -2773,12 +2773,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Greška kod učitavanja wallet.dat: Novčanik zahtjeva noviju verziju Bitcoina - + Wallet needed to be rewritten: restart Bitcoin to complete Novčanik je trebao prepravak: ponovo pokrenite Bitcoin - + Error loading wallet.dat Greška kod učitavanja wallet.dat @@ -2788,7 +2788,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevaljala -proxy adresa: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2808,7 +2808,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Nevaljali iznos za opciju -paytxfee=<amount>: '%s' @@ -2828,7 +2828,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Učitavanje indeksa blokova... - + Add a node to connect to and attempt to keep the connection open Unesite nod s kojim se želite spojiti and attempt to keep the connection open @@ -2838,7 +2838,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Program ne može koristiti %s na ovom računalu. Bitcoin program je vjerojatno već pokrenut. - + Fee per KB to add to transactions you send Naknada posredniku po KB-u koja će biti dodana svakoj transakciji koju pošalješ @@ -2848,15 +2848,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Učitavanje novčanika... - + Cannot downgrade wallet Nije moguće novčanik vratiti na prijašnju verziju. - - - Cannot initialize keypool - Keypool nije moguće inicijalizirati. - Cannot write default address @@ -2868,22 +2863,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescaniranje - + Done loading Učitavanje gotovo - + To use the %s option - + Error Greška - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index 5e885b0c2..3f0e6b955 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -322,17 +322,17 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt BitcoinGUI - + Sign &message... Üzenet aláírása... - + Synchronizing with network... Szinkronizálás a hálózattal... - + &Overview &Áttekintés @@ -407,7 +407,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Jelszó &megváltoztatása... - + Importing blocks from disk... A blokkok importálása lemezről... @@ -417,7 +417,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt A blokkok lemezen történő ujraindexelése... - + Send coins to a Bitcoin address Érmék küldése megadott címre @@ -452,18 +452,18 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Üzenet &valódiságának ellenőrzése - - + + Bitcoin Bitcoin - + Wallet Tárca - + &Send @@ -539,7 +539,7 @@ Ez a termék az OpenSSL Project által lett kifejlesztve az OpenSSL Toolkit (htt Bitcoin kliens - + %n active connection(s) to Bitcoin network %n aktív kapcsolat a Bitcoin-hálózattal%n aktív kapcsolat a Bitcoin-hálózattal @@ -669,7 +669,7 @@ Cím: %4 Tárca <b>kódolva</b> és jelenleg <b>zárva</b>. - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -809,8 +809,8 @@ Cím: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Opcionális, kB-onkénti tranzakciós díj a tranzakcióid minél gyorsabb feldolgozásának elősegítésére. A legtöbb tranzakció 1 kB-os. 0,01 BTC ajánlott. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2136,12 +2136,17 @@ Cím: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Jelenlegi nézet exportálása fájlba - + Backup Wallet Biztonsági másolat készítése a Tárcáról @@ -2174,12 +2179,12 @@ Cím: %4 bitcoin-core - + Bitcoin version Bitcoin verzió - + Usage: Használat: @@ -2190,7 +2195,7 @@ Cím: %4 - + List commands Parancsok kilistázása @@ -2202,7 +2207,7 @@ Cím: %4 - + Options: Opciók @@ -2220,19 +2225,7 @@ Cím: %4 - - Generate coins - Érmék generálása - - - - - Don't generate coins - Bitcoin-generálás leállítása - - - - + Specify data directory Adatkönyvtár @@ -2243,7 +2236,7 @@ Cím: %4 Az adatbázis gyorsítótár mérete megabájtban (alapértelmezés: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Csatlakozásokhoz figyelendő <port> (alapértelmezett: 8333 or testnet: 18333) @@ -2253,7 +2246,7 @@ Cím: %4 Maximálisan <n> számú kapcsolat fenntartása a peerekkel (alapértelmezés: 125) - + Connect to a node to retrieve peer addresses, and disconnect Kapcsolódás egy csomóponthoz a peerek címeinek megszerzése miatt, majd szétkapcsolás @@ -2273,23 +2266,23 @@ Cím: %4 Helytelenül viselkedő peerek kizárási ideje másodpercben (alapértelmezés: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) JSON-RPC csatlakozásokhoz figyelendő <port> (alapértelmezett: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Parancssoros és JSON-RPC parancsok elfogadása - + Run in the background as a daemon and accept commands Háttérben futtatás daemonként és parancsok elfogadása @@ -2301,12 +2294,12 @@ Cím: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2335,11 +2328,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2366,12 +2354,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2411,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) Csatlakozás csak a megadott csomóponthoz @@ -2431,7 +2414,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2531,7 +2514,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2541,7 +2529,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2561,12 +2554,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2591,7 +2589,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) Csak blokklánccal egyező beépített ellenőrző pontok elfogadása (alapértelmezés: 1) @@ -2708,13 +2706,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address JSON-RPC csatlakozások engedélyezése meghatározott IP-címről - + Send commands to node running on <ip> (default: 127.0.0.1) Parancsok küldése <ip> címen működő csomóponthoz (alapértelmezett: 127.0.0.1) @@ -2760,13 +2758,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Elfogadható rejtjelkulcsok (alapértelmezett: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH ) - + This help message Ez a súgó-üzenet @@ -2782,12 +2780,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Csatlakozás SOCKS proxyn keresztül - + Allow DNS lookups for -addnode, -seednode and -connect DNS-kikeresés engedélyezése az addnode-nál és a connect-nél - + Loading addresses... Címek betöltése... @@ -2802,12 +2800,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Hiba a wallet.dat betöltése közben: ehhez a tárcához újabb verziójú Bitcoin-kliens szükséges - + Wallet needed to be rewritten: restart Bitcoin to complete A Tárca újraírása szükséges: Indítsa újra a teljesen a Bitcoin-t - + Error loading wallet.dat Hiba az wallet.dat betöltése közben @@ -2817,7 +2815,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Érvénytelen -proxy cím: '%s' - + Unknown network specified in -onlynet: '%s' Ismeretlen hálózat lett megadva -onlynet: '%s' @@ -2837,7 +2835,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Étvénytelen -paytxfee=<összeg> összeg: '%s' @@ -2857,7 +2855,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Blokkindex betöltése... - + Add a node to connect to and attempt to keep the connection open Elérendő csomópont megadása and attempt to keep the connection open @@ -2867,7 +2865,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. A %s nem elérhető ezen a gépen. A Bitcoin valószínűleg fut már. - + Fee per KB to add to transactions you send kB-onként felajánlandó díj az általad küldött tranzakciókhoz @@ -2877,15 +2875,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Tárca betöltése... - + Cannot downgrade wallet Nem sikerült a Tárca visszaállítása a korábbi verzióra - - - Cannot initialize keypool - Nem lehet a keypool-t inicializálni - Cannot write default address @@ -2897,22 +2890,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Újraszkennelés... - + Done loading Betöltés befejezve. - + To use the %s option Használd a %s opciót - + Error Hiba - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index 15e154e0b..b634486e2 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -323,17 +323,17 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso BitcoinGUI - + Sign &message... Firma il &messaggio... - + Synchronizing with network... Sto sincronizzando con la rete... - + &Overview &Sintesi @@ -408,7 +408,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso &Cambia la passphrase... - + Importing blocks from disk... Importa blocchi dal disco... @@ -418,7 +418,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Re-indicizzazione blocchi su disco... - + Send coins to a Bitcoin address Invia monete ad un indirizzo bitcoin @@ -453,18 +453,18 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso &Verifica messaggio... - - + + Bitcoin Bitcoin - + Wallet Portamonete - + &Send &Spedisci @@ -540,7 +540,7 @@ Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso Bitcoin client - + %n active connection(s) to Bitcoin network %n connessione attiva alla rete Bitcoin%n connessioni attive alla rete Bitcoin @@ -671,7 +671,7 @@ Indirizzo: %4 Il portamonete è <b>cifrato</b> e attualmente <b>bloccato</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Riscontrato un errore irreversibile. Bitcoin non può più continuare in sicurezza e verrà terminato. @@ -811,8 +811,8 @@ Indirizzo: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Commissione di transazione per kB; è opzionale e contribuisce ad assicurare che le transazioni siano elaborate velocemente. Le transazioni sono per la maggior parte da 1 kB. Commissione raccomandata 0,01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2137,12 +2137,17 @@ Indirizzo: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Esporta i dati nella tabella corrente su un file - + Backup Wallet @@ -2175,12 +2180,12 @@ Indirizzo: %4 bitcoin-core - + Bitcoin version Versione di Bitcoin - + Usage: Utilizzo: @@ -2191,7 +2196,7 @@ Indirizzo: %4 - + List commands Lista comandi @@ -2203,7 +2208,7 @@ Indirizzo: %4 - + Options: Opzioni: @@ -2221,19 +2226,7 @@ Indirizzo: %4 - - Generate coins - Genera Bitcoin - - - - - Don't generate coins - Non generare Bitcoin - - - - + Specify data directory Specifica la cartella dati @@ -2244,7 +2237,7 @@ Indirizzo: %4 Imposta la dimensione cache del database in megabyte (default: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Ascolta le connessioni JSON-RPC su <porta> (default: 8333 o testnet: 18333) @@ -2254,7 +2247,7 @@ Indirizzo: %4 Mantieni al massimo <n> connessioni ai peer (default: 125) - + Connect to a node to retrieve peer addresses, and disconnect Connessione ad un nodo per ricevere l'indirizzo del peer, e disconnessione @@ -2274,23 +2267,23 @@ Indirizzo: %4 Numero di secondi di sospensione che i peer di cattiva qualità devono trascorrere prima di riconnettersi (default: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Errore riscontrato durante l'impostazione della porta RPC %u per l'ascolto su IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Attendi le connessioni JSON-RPC su <porta> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Accetta da linea di comando e da comandi JSON-RPC - + Run in the background as a daemon and accept commands Esegui in background come demone e accetta i comandi @@ -2302,12 +2295,12 @@ Indirizzo: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) Accetta connessioni dall'esterno (default: 1 se no -proxy o -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2336,11 +2329,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Non è possibile ottenere i dati sulla cartella %s. Probabilmente Bitcoin è già in esecuzione. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Errore nell'inizializzazione dell'ambiente del database %s! Per ripristinare, FAI UN BACKUP DI QUELLA CARTELLA, poi rimuovi tutto all'interno eccetto wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2367,12 +2355,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Imposta dimensione massima delle transazioni ad alta priorità/bassa-tassa in bytes (predefinito: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Questa versione è una compilazione pre-rilascio - usala a tuo rischio - non utilizzarla per la generazione o per applicazioni di commercio @@ -2412,7 +2395,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Opzioni creazione blocco: - + Connect only to the specified node(s) Connetti solo al nodo specificato @@ -2432,7 +2415,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Vuoi ricostruire ora il database dei blocchi? - + Error initializing block database @@ -2532,7 +2515,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Trova peer utilizzando la ricerca DNS (predefinito: 1 finché utilizzato -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Quanti blocchi da controllare all'avvio (predefinito: 288, 0 = tutti) @@ -2542,7 +2530,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2562,12 +2555,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verifica portafoglio... - + Imports blocks from external blk000??.dat file Importa blocchi da un file blk000??.dat esterno - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Informazione @@ -2592,7 +2590,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Buffer di invio massimo per connessione, <n>*1000 byte (default: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2709,13 +2707,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address Consenti connessioni JSON-RPC dall'indirizzo IP specificato - + Send commands to node running on <ip> (default: 127.0.0.1) Inviare comandi al nodo in esecuzione su <ip> (default: 127.0.0.1) @@ -2761,13 +2759,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrari accettabili (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Questo messaggio di aiuto @@ -2783,13 +2781,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Connessione tramite socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Consenti ricerche DNS per aggiungere nodi e collegare - + Loading addresses... Caricamento indirizzi... @@ -2804,12 +2802,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Errore caricamento wallet.dat: il wallet richiede una versione nuova di Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Il portamonete deve essere riscritto: riavviare Bitcoin per completare - + Error loading wallet.dat Errore caricamento wallet.dat @@ -2819,7 +2817,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Indirizzo -proxy non valido: '%s' - + Unknown network specified in -onlynet: '%s' Rete sconosciuta specificata in -onlynet: '%s' @@ -2839,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossibile risolvere indirizzo -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Importo non valido per -paytxfee=<amount>: '%s' @@ -2859,7 +2857,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Caricamento dell'indice del blocco... - + Add a node to connect to and attempt to keep the connection open Elérendő csomópont megadása and attempt to keep the connection open @@ -2869,7 +2867,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossibile collegarsi alla %s su questo computer. Probabilmente Bitcoin è già in esecuzione. - + Fee per KB to add to transactions you send Commissione per KB da aggiungere alle transazioni in uscita @@ -2879,15 +2877,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Caricamento portamonete... - + Cannot downgrade wallet Non è possibile retrocedere il wallet - - - Cannot initialize keypool - Non è possibile iniziare la keypool - Cannot write default address @@ -2899,22 +2892,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ripetere la scansione... - + Done loading Caricamento completato - + To use the %s option Per usare la opzione %s - + Error Errore - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index da4c99be8..18a663540 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... ネットワークと同期化中。。。 - + &Overview &概観 @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 財布は<b>暗号化とロックです</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version Bitcoin Bertsio - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index 64c26ff43..f92c3daf6 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -322,17 +322,17 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op BitcoinGUI - + Sign &message... Signa &nuntium... - + Synchronizing with network... Synchronizans cum rete... - + &Overview &Summarium @@ -407,7 +407,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op &Muta tesseram... - + Importing blocks from disk... Importans frusta ab disco... @@ -417,7 +417,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Recreans indicem frustorum in disco... - + Send coins to a Bitcoin address Mitte nummos ad inscriptionem Bitcoin @@ -452,18 +452,18 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op &Verifica nuntium... - - + + Bitcoin Bitcoin - + Wallet Cassidile - + &Send &Mitte @@ -539,7 +539,7 @@ Hoc productum continet programmata composita ab OpenSSL Project pro utendo in Op Bitcoin cliens - + %n active connection(s) to Bitcoin network %n activa conexio ad rete Bitcoin%n activae conexiones ad rete Bitcoin @@ -669,7 +669,7 @@ Inscriptio: %4 Cassidile <b>cifratum</b> est et iam nunc <b>seratum</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Error fatalis accidit. Bitcoin nondum pergere tute potest, et exibit. @@ -808,8 +808,8 @@ Inscriptio: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Optionalis merces transactionum singulis kB quae adiuvat curare ut tuae transactiones processae sit celeriter. Plurimi transactiones 1kB sunt. Merces 0.01 hortata. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2134,12 +2134,17 @@ Inscriptio: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Exporta data in hac tabella in plicam - + Backup Wallet Conserva cassidile @@ -2172,12 +2177,12 @@ Inscriptio: %4 bitcoin-core - + Bitcoin version Versio de Bitcoin - + Usage: Usus: @@ -2187,7 +2192,7 @@ Inscriptio: %4 Mitte mandatum ad -server vel bitcoind - + List commands Enumera mandata @@ -2197,7 +2202,7 @@ Inscriptio: %4 Accipe auxilium pro mandato - + Options: Optiones: @@ -2212,17 +2217,7 @@ Inscriptio: %4 Specifica pid plicam (praedefinitum: bitcoin.pid) - - Generate coins - Genera nummos - - - - Don't generate coins - Nolite nummos generare - - - + Specify data directory Specifica indicem datorum @@ -2232,7 +2227,7 @@ Inscriptio: %4 Constitue magnitudinem databasis cache in megabytes (praedefinitum: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Ausculta pro conexionibus in <porta> (praedefinitum: 8333 vel testnet: 18333) @@ -2242,7 +2237,7 @@ Inscriptio: %4 Manutene non plures quam <n> conexiones ad paria (praedefinitum: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conecta ad nodum acceptare inscriptiones parium, et disconecte @@ -2262,22 +2257,22 @@ Inscriptio: %4 Numerum secundorum prohibere ne paria improba reconectant (praedefinitum: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Error erat dum initians portam RPC %u pro auscultando in IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Ausculta pro conexionibus JSON-RPC in <porta> (praedefinitum: 8332 vel testnet: 18332) - + Accept command line and JSON-RPC commands Accipe terminalis et JSON-RPC mandata. - + Run in the background as a daemon and accept commands Operare infere sicut daemon et mandata accipe @@ -2287,12 +2282,12 @@ Inscriptio: %4 Utere rete experimentale - + Accept connections from outside (default: 1 if no -proxy or -connect) Accipe conexiones externas (praedefinitum: 1 nisi -proxy neque -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2331,11 +2326,6 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Non posse serare datorum indicem %s. Bitcoin probabiliter iam operatur. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Error initiando systema databasi %s! Ut restituas, CONSERVA ILLUM INDICEM PLICARUM, tunc remove omnes ex illo praeter wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2362,12 +2352,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Constitue magnitudinem maximam transactionum magnae-prioritatis/parvae-mercedis in octetis/bytes (praedefinitum: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Constitue numerum filorum verificationis scriptorum (1-16, 0=auto, praedefinitum: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Hoc est prae-dimittum experimentala aedes - utere eo periculo tuo proprio - nolite utere fodendo vel applicationibus mercatoriis @@ -2407,7 +2392,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Optiones creandi frustorum: - + Connect only to the specified node(s) Conecte sole ad nodos specificatos (vel nodum specificatum) @@ -2427,7 +2412,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Visne reficere databasum frustorum iam? - + Error initializing block database Error initiando databasem frustorum @@ -2527,7 +2512,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Inveni paria utendo DNS quaerendo (praedefinitum: 1 nisi -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Quot frusta proba ad initium (praedefinitum: 288, 0 = omnia) @@ -2537,7 +2527,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Quam perfecta frustorum verificatio est (0-4, praedefinitum: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Restituere indicem catenae frustorum ex activis plicis blk000??.dat @@ -2557,12 +2552,17 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Verificante cassidilem... - + Imports blocks from external blk000??.dat file Importat frusta ab externa plica blk000??.dat - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Informatio @@ -2587,7 +2587,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Maxima magnitudo memoriae pro datis mittendis singulis conexionibus, <n>*1000 octetis/bytes (praedefinitum: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Tantum accipe catenam frustorum convenientem internis lapidibus (praedefinitum: 1) @@ -2702,12 +2702,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Tessera pro conexionibus JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitte conexionibus JSON-RPC ex inscriptione specificata - + Send commands to node running on <ip> (default: 127.0.0.1) Mitte mandata nodo operanti in <ip> (praedefinitum: 127.0.0.1) @@ -2747,12 +2747,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Clavis privata daemonis moderans (praedefinitum: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Acceptabiles cifrae (praedefinitum: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Hic nuntius auxilii @@ -2767,12 +2767,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Conecte per socks vicarium - + Allow DNS lookups for -addnode, -seednode and -connect Permitte quaerenda DNS pro -addnode, -seednode, et -connect - + Loading addresses... Legens inscriptiones... @@ -2787,12 +2787,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Error legendi wallet.dat: Cassidili necesse est recentior versio Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Cassidili necesse erat rescribi: Repelle Bitcoin ut compleas - + Error loading wallet.dat Error legendi wallet.dat @@ -2802,7 +2802,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Inscriptio -proxy non valida: '%s' - + Unknown network specified in -onlynet: '%s' Ignotum rete specificatum in -onlynet: '%s' @@ -2822,7 +2822,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Non posse resolvere -externalip inscriptionem: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantitas non valida pro -paytxfee=<quantitas>: '%s' @@ -2842,7 +2842,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Legens indicem frustorum... - + Add a node to connect to and attempt to keep the connection open Adice nodum cui conectere et conare sustinere conexionem apertam @@ -2852,7 +2852,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Non posse conglutinare ad %s in hoc cumputatro. Bitcoin probabiliter iam operatur. - + Fee per KB to add to transactions you send Merces per KB addere ad transactiones tu mittas @@ -2862,15 +2862,10 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Legens cassidile... - + Cannot downgrade wallet Non posse cassidile regredi - - - Cannot initialize keypool - Non posse initiare stagnum clavium - Cannot write default address @@ -2882,22 +2877,22 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Iterum perlegens... - + Done loading Completo lengendi - + To use the %s option Ut utaris optione %s - + Error Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index d46baa341..99c82f549 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -322,17 +322,17 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. BitcoinGUI - + Sign &message... Pasirašyti ži&nutę... - + Synchronizing with network... Sinchronizavimas su tinklu ... - + &Overview &Apžvalga @@ -407,7 +407,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. &Keisti slaptafrazę... - + Importing blocks from disk... @@ -417,7 +417,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. - + Send coins to a Bitcoin address Siųsti monetas Bitcoin adresui @@ -452,18 +452,18 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. &Tikrinti žinutę... - - + + Bitcoin Bitcoin - + Wallet Piniginė - + &Send @@ -539,7 +539,7 @@ Platinama pagal MIT/X11 licenciją, kurią rasite faile COPYING arba http://www. Bitcoin klientas - + %n active connection(s) to Bitcoin network %n Bitcoin tinklo aktyvus ryšys%n Bitcoin tinklo aktyvūs ryšiai%n Bitcoin tinklo aktyvūs ryšiai @@ -668,7 +668,7 @@ Adresas: %4 Piniginė <b>užšifruota</b> ir šiuo metu <b>užrakinta</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -807,8 +807,8 @@ Adresas: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Neprivalomas sandorio mokestis už KB, kuris padeda greičiau sutvarkyti sandorius. Daugelis sandorių yra tik 1KB dydžio. Rekomenduojamas 0,01 mokestis. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2133,12 +2133,17 @@ Adresas: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2171,12 +2176,12 @@ Adresas: %4 bitcoin-core - + Bitcoin version Bitcoin versija - + Usage: Naudojimas: @@ -2186,7 +2191,7 @@ Adresas: %4 Siųsti komandą serveriui arba bitcoind - + List commands Komandų sąrašas @@ -2196,7 +2201,7 @@ Adresas: %4 Suteikti pagalba komandai - + Options: Parinktys: @@ -2211,17 +2216,7 @@ Adresas: %4 Nurodyti pid failą (pagal nutylėjimą: bitcoind.pid) - - Generate coins - Generuoti monetas - - - - Don't generate coins - Negeneruoti monetų - - - + Specify data directory Nustatyti duomenų aplanką @@ -2231,7 +2226,7 @@ Adresas: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) Sujungimo klausymas prijungčiai <port> (pagal nutylėjimą: 8333 arba testnet: 18333) @@ -2241,7 +2236,7 @@ Adresas: %4 Palaikyti ne daugiau <n> jungčių kolegoms (pagal nutylėjimą: 125) - + Connect to a node to retrieve peer addresses, and disconnect @@ -2261,22 +2256,22 @@ Adresas: %4 Sekundžių kiekis eikiamas palaikyti ryšį dėl lygiarangių nestabilumo (pagal nutylėjimą: 86.400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Klausymas JSON-RPC sujungimui prijungčiai <port> (pagal nutylėjimą: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Priimti komandinę eilutę ir JSON-RPC komandas - + Run in the background as a daemon and accept commands Dirbti fone kaip šešėlyje ir priimti komandas @@ -2286,12 +2281,12 @@ Adresas: %4 Naudoti testavimo tinklą - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2320,11 +2315,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2351,12 +2341,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2396,7 +2381,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) Prisijungti tik prie nurodyto mazgo @@ -2416,7 +2401,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2516,7 +2501,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2526,7 +2516,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2546,12 +2541,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2576,7 +2576,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Maksimalus buferis siuntimo sujungimui <n>*1000 bitų (pagal nutylėjimą: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2691,12 +2691,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Slaptažodis JSON-RPC sujungimams - + Allow JSON-RPC connections from specified IP address Leisti JSON-RPC tik iš nurodytų IP adresų - + Send commands to node running on <ip> (default: 127.0.0.1) Siųsti komandą mazgui dirbančiam <ip> (pagal nutylėjimą: 127.0.0.1) @@ -2736,12 +2736,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Serverio privatus raktas (pagal nutylėjimą: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Priimtini šifrai (pagal nutylėjimą: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Pagelbos žinutė @@ -2756,12 +2756,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Jungtis per socks tarpinį serverį - + Allow DNS lookups for -addnode, -seednode and -connect Leisti DNS paiešką sujungimui ir mazgo pridėjimui - + Loading addresses... Užkraunami adresai... @@ -2776,12 +2776,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat pakrovimo klaida, wallet.dat reikalauja naujasnės Bitcoin versijos - + Wallet needed to be rewritten: restart Bitcoin to complete Piniginė turi būti prrašyta: įvykdymui perkraukite Bitcoin - + Error loading wallet.dat wallet.dat pakrovimo klaida @@ -2791,7 +2791,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Neteisingas proxy adresas: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2811,7 +2811,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Neteisinga suma -paytxfee=<amount>: '%s' @@ -2831,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Įkeliamas blokų indeksas... - + Add a node to connect to and attempt to keep the connection open Pridėti mazgą prie sujungti su and attempt to keep the connection open @@ -2841,7 +2841,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nepavyko susieti šiame kompiuteryje prievado %s. Bitcoin tikriausiai jau veikia. - + Fee per KB to add to transactions you send Įtraukti mokestį už kB siunčiamiems sandoriams @@ -2851,15 +2851,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Užkraunama piniginė... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2871,22 +2866,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Peržiūra - + Done loading Įkėlimas baigtas - + To use the %s option - + Error Klaida - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index 53f36523f..e661ad860 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Parakstīt &ziņojumu... - + Synchronizing with network... Sinhronizācija ar tīklu... - + &Overview &Pārskats @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Mainīt paroli - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address Nosūtīt bitkoinus uz Bitcoin adresi @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Pārbaudīt ziņojumu... - - + + Bitcoin - + Wallet Maciņš - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin klients - + %n active connection(s) to Bitcoin network %n aktīvu savienojumu ar Bitcoin tīklu%n aktīvs savienojums ar Bitcoin tīklu%n aktīvu savienojumu as Bitcoin tīklu @@ -665,7 +665,7 @@ Adrese: %4 Maciņš ir <b>šifrēts</b> un pašlaik <b>slēgts</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -804,8 +804,8 @@ Adrese: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Brīvprātīga maksa par transakcijas kB, kas nodrošina ātru transakciju apstrādi. Vairums transakciju aizņem 1 kB. Ieteicamā maksa 0.01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2130,12 +2130,17 @@ Adrese: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet Izveidot maciņa rezerves kopiju @@ -2168,12 +2173,12 @@ Adrese: %4 bitcoin-core - + Bitcoin version Bitcoin versija - + Usage: Lietojums: @@ -2183,7 +2188,7 @@ Adrese: %4 Nosūtīt komantu uz -server vai bitcoind - + List commands Komandu saraksts @@ -2193,7 +2198,7 @@ Adrese: %4 Palīdzība par komandu - + Options: Iespējas: @@ -2208,17 +2213,7 @@ Adrese: %4 Norādiet pid failu (pēc noklusēšanas: bitcoind.pid) - - Generate coins - Bitkoinu ģenerēšana - - - - Don't generate coins - Neģenerēt bitkoinus - - - + Specify data directory Norādiet datu direktoriju @@ -2228,7 +2223,7 @@ Adrese: %4 Uzstādiet datu bāzes bufera izmēru megabaitos (pēc noklusēšanas: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Gaidīt savienojumus portā <port> (pēc noklusēšanas: 8333 vai testnet: 18333) @@ -2238,7 +2233,7 @@ Adrese: %4 Uzturēt līdz <n> savienojumiem ar citiem mezgliem(pēc noklusēšanas: 125) - + Connect to a node to retrieve peer addresses, and disconnect Pievienoties mezglam, lai iegūtu citu mezglu adreses, un atvienoties @@ -2258,22 +2253,22 @@ Adrese: %4 Sekundes, cik ilgi atturēt pārkāpējmezglus no atkārtotas pievienošanās (pēc noklusēšanas: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Pieņemt komandrindas un JSON-RPC komandas - + Run in the background as a daemon and accept commands Darbināt fonā kā servisu un pieņemt komandas @@ -2283,12 +2278,12 @@ Adrese: %4 Izmantot testa tīklu - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2317,11 +2312,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2348,12 +2338,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2393,7 +2378,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2413,7 +2398,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2513,7 +2498,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2523,7 +2513,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2543,12 +2538,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2573,7 +2573,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2688,12 +2688,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. JSON-RPC savienojumu parole - + Allow JSON-RPC connections from specified IP address Atļaut JSON-RPC savienojumus no norādītās IP adreses - + Send commands to node running on <ip> (default: 127.0.0.1) Nosūtīt komandas mezglam, kas darbojas adresē <ip> (pēc noklusēšanas: 127.0.0.1) @@ -2733,12 +2733,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Servera privātā atslēga (pēc noklusēšanas: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Pieņemamie šifri (pēc noklusēšanas: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Šis palīdzības paziņojums @@ -2753,12 +2753,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Savienoties caurs socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Atļaut DNS uzmeklēšanu priekš -addnode, -seednode un -connect - + Loading addresses... Ielādē adreses... @@ -2773,12 +2773,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar ielādēt wallet.dat: maciņa atvēršanai nepieciešama jaunāka Bitcoin versija - + Wallet needed to be rewritten: restart Bitcoin to complete Bija nepieciešams pārstartēt maciņu: pabeigšanai pārstartējiet Bitcoin - + Error loading wallet.dat Kļūda ielādējot wallet.dat @@ -2788,7 +2788,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nederīga -proxy adrese: '%s' - + Unknown network specified in -onlynet: '%s' -onlynet komandā norādīts nepazīstams tīkls: '%s' @@ -2808,7 +2808,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar atrisināt -externalip adresi: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Nederīgs daudzums priekš -paytxfree=<amount>: '%s' @@ -2828,7 +2828,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ielādē bloku indeksu... - + Add a node to connect to and attempt to keep the connection open Pievienot mezglu, kam pievienoties un turēt savienojumu atvērtu @@ -2838,7 +2838,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar pievienoties %s uz šī datora. Bitcoin droši vien jau darbojas. - + Fee per KB to add to transactions you send Maksa par KB, ko pievienot nosūtāmajām transakcijām @@ -2848,15 +2848,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ielādē maciņu... - + Cannot downgrade wallet Nevar maciņa formātu padarīt vecāku - - - Cannot initialize keypool - Nevar inicializēt atslēgu buferi - Cannot write default address @@ -2868,22 +2863,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Skanēju no jauna... - + Done loading Ielāde pabeigta - + To use the %s option Izmantot opciju %s - + Error Kļūda - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 6a62cad33..2d949897e 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -323,17 +323,17 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i BitcoinGUI - + Sign &message... Signer &melding... - + Synchronizing with network... Synkroniserer med nettverk... - + &Overview &Oversikt @@ -408,7 +408,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i &Endre Adgangsfrase... - + Importing blocks from disk... Importere blokker... @@ -418,7 +418,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Re-indekserer blokker på disk... - + Send coins to a Bitcoin address Send til en Bitcoin-adresse @@ -453,18 +453,18 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i &Verifiser melding... - - + + Bitcoin Bitcoin - + Wallet Lommebok - + &Send &Send @@ -540,7 +540,7 @@ Dette produktet inneholder programvare utviklet av OpenSSL prosjektet for bruk i Bitcoinklient - + %n active connection(s) to Bitcoin network %n aktiv forbindelse til Bitcoin-nettverket%n aktive forbindelser til Bitcoin-nettverket @@ -670,7 +670,7 @@ Adresse: %4 Lommeboken er <b>kryptert</b> og for tiden <b>låst</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. En fatal feil har inntruffet. Det er ikke trygt å fortsette og Bitcoin må derfor avslutte. @@ -810,8 +810,8 @@ Adresse: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Valgfritt transaksjonsgebyr per kB som sikrer at dine transaksjoner blir raskt prosessert. De fleste transaksjoner er 1 kB. Et gebyr på 0.01 er anbefalt. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2136,12 +2136,17 @@ Adresse: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Eksporter data fra nåværende fane til fil - + Backup Wallet Sikkerhetskopier lommebok @@ -2174,12 +2179,12 @@ Adresse: %4 bitcoin-core - + Bitcoin version Bitcoin versjon - + Usage: Bruk: @@ -2189,7 +2194,7 @@ Adresse: %4 Send kommando til -server eller bitcoind - + List commands List opp kommandoer @@ -2199,7 +2204,7 @@ Adresse: %4 Vis hjelpetekst for en kommando - + Options: Innstillinger: @@ -2214,17 +2219,7 @@ Adresse: %4 Angi pid-fil (standardverdi: bitcoind.pid) - - Generate coins - Generér bitcoins - - - - Don't generate coins - Ikke generér bitcoins - - - + Specify data directory Angi mappe for datafiler @@ -2234,7 +2229,7 @@ Adresse: %4 Sett størrelse på mellomlager for database i megabytes (standardverdi: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Lytt etter tilkoblinger på <port> (standardverdi: 8333 eller testnet: 18333) @@ -2244,7 +2239,7 @@ Adresse: %4 Hold maks <n> koblinger åpne til andre noder (standardverdi: 125) - + Connect to a node to retrieve peer addresses, and disconnect Koble til node for å hente adresser til andre noder, koble så fra igjen @@ -2264,22 +2259,22 @@ Adresse: %4 Antall sekunder noder med dårlig oppførsel hindres fra å koble til på nytt (standardverdi: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s En feil oppstod ved opprettelse av RPC port %u for lytting: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Lytt etter JSON-RPC tilkoblinger på <port> (standardverdi: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Ta imot kommandolinje- og JSON-RPC-kommandoer - + Run in the background as a daemon and accept commands Kjør i bakgrunnen som daemon og ta imot kommandoer @@ -2289,12 +2284,12 @@ Adresse: %4 Bruk testnettverket - + Accept connections from outside (default: 1 if no -proxy or -connect) Ta imot tilkoblinger fra utsiden (standardverdi: 1 hvis uten -proxy eller -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2332,11 +2327,6 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2363,12 +2353,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Sett maks størrelse for transaksjoner med høy prioritet / lavt gebyr, i bytes (standardverdi: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2408,7 +2393,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Valg for opprettelse av blokker: - + Connect only to the specified node(s) Koble kun til angitt(e) node(r) @@ -2428,7 +2413,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Ønsker du å gjenopprette blokkdatabasen nå? - + Error initializing block database @@ -2528,7 +2513,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Finn andre noder gjennom DNS-oppslag (standardverdi: 1 med mindre -connect er oppgit) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2538,7 +2528,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Gjenopprett blokkjedeindex fra blk000??.dat filer @@ -2558,12 +2553,17 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Verifiserer lommebok... - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2588,7 +2588,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Maks sendebuffer per forbindelse, <n>*1000 bytes (standardverdi: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2703,12 +2703,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Passord for JSON-RPC forbindelser - + Allow JSON-RPC connections from specified IP address Tillat JSON-RPC tilkoblinger fra angitt IP-adresse - + Send commands to node running on <ip> (default: 127.0.0.1) Send kommandoer til node på <ip> (standardverdi: 127.0.0.1) @@ -2748,12 +2748,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Servers private nøkkel (standardverdi: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akseptable krypteringsmetoder (standardverdi: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Denne hjelpemeldingen @@ -2768,12 +2768,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Koble til gjennom socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Tillat DNS oppslag for -addnode, -seednode og -connect - + Loading addresses... Laster adresser... @@ -2788,12 +2788,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Feil ved lasting av wallet.dat: Lommeboken krever en nyere versjon av Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Lommeboken måtte skrives om: start Bitcoin på nytt for å fullføre - + Error loading wallet.dat Feil ved lasting av wallet.dat @@ -2803,7 +2803,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Ugyldig -proxy adresse: '%s' - + Unknown network specified in -onlynet: '%s' Ukjent nettverk angitt i -onlynet '%s' @@ -2823,7 +2823,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Kunne ikke slå opp -externalip adresse: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ugyldig beløp for -paytxfee=<beløp>: '%s' @@ -2843,7 +2843,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Laster blokkindeks... - + Add a node to connect to and attempt to keep the connection open Legg til node for tilkobling og hold forbindelsen åpen @@ -2853,7 +2853,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Kan ikke binde til %s på denne datamaskinen. Sannsynligvis kjører Bitcoin allerede. - + Fee per KB to add to transactions you send Gebyr per KB for transaksjoner du sender @@ -2863,15 +2863,10 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Laster lommebok... - + Cannot downgrade wallet Kan ikke nedgradere lommebok - - - Cannot initialize keypool - Kan ikke initialisere nøkkellager - Cannot write default address @@ -2883,22 +2878,22 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Leser gjennom... - + Done loading Ferdig med lasting - + To use the %s option For å bruke %s opsjonen - + Error Feil - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index c059a1f9f..5926119cf 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -323,17 +323,17 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d BitcoinGUI - + Sign &message... &Onderteken bericht... - + Synchronizing with network... Synchroniseren met netwerk... - + &Overview &Overzicht @@ -408,7 +408,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d &Wijzig Wachtwoord - + Importing blocks from disk... Blokken aan het importeren vanaf harde schijf... @@ -418,7 +418,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Bezig met herindexeren van blokken op harde schijf... - + Send coins to a Bitcoin address Verstuur munten naar een Bitcoinadres @@ -453,18 +453,18 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d &Verifiëer bericht... - - + + Bitcoin Bitcoin - + Wallet Portemonnee - + &Send &Versturen @@ -540,7 +540,7 @@ Dit product bevat software ontwikkeld door het OpenSSL Project voor gebruik in d Bitcoin client - + %n active connection(s) to Bitcoin network %n actieve connectie naar Bitcoinnetwerk%n actieve connecties naar Bitcoinnetwerk @@ -670,7 +670,7 @@ Adres: %4 Portemonnee is <b>versleuteld</b> en momenteel <b>gesloten</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Er is een fatale fout opgetreden. Bitcoin kan niet meer veilig doorgaan en zal nu afgesloten worden. @@ -809,8 +809,8 @@ Adres: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Optionele transactiekosten per kB die helpen om uw transacties snel te verwerken. De meeste transacties zijn 1 kB. Transactiekosten van 0,01 wordt aangeraden + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Optionele transactiekosten per kB. Transactiekosten helpen ervoor te zorgen dat uw transacties snel verwerkt worden. De meeste transacties zijn 1kB. @@ -2135,12 +2135,17 @@ Adres: %4 WalletView - + + &Export + &Exporteer + + + Export the data in the current tab to a file Exporteer de data in de huidige tab naar een bestand - + Backup Wallet Portomonnee backuppen @@ -2173,12 +2178,12 @@ Adres: %4 bitcoin-core - + Bitcoin version Bitcoinversie - + Usage: Gebruik: @@ -2188,7 +2193,7 @@ Adres: %4 Stuur commando naar -server of bitcoind - + List commands Lijst van commando's @@ -2198,7 +2203,7 @@ Adres: %4 Toon hulp voor een commando - + Options: Opties: @@ -2215,19 +2220,7 @@ Adres: %4 - - Generate coins - Genereer munten - - - - - Don't generate coins - Genereer geen munten - - - - + Specify data directory Stel datamap in @@ -2237,7 +2230,7 @@ Adres: %4 Stel databankcachegrootte in in megabytes (standaard: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Luister voor verbindingen op <poort> (standaard: 8333 of testnet: 18333) @@ -2247,7 +2240,7 @@ Adres: %4 Onderhoud maximaal <n> verbindingen naar peers (standaard: 125) - + Connect to a node to retrieve peer addresses, and disconnect Verbind naar een node om adressen van anderen op te halen, en verbreek vervolgens de verbinding @@ -2267,22 +2260,22 @@ Adres: %4 Aantal seconden dat zich misdragende peers niet opnieuw mogen verbinden (standaard: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Er is een fout opgetreden tijdens het instellen van de inkomende RPC-poort %u op IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Wacht op JSON-RPC-connecties op poort <port> (standaard: 8332 of testnet: 18332) - + Accept command line and JSON-RPC commands Aanvaard commandoregel- en JSON-RPC-commando's - + Run in the background as a daemon and accept commands Draai in de achtergrond als daemon en aanvaard commando's @@ -2292,12 +2285,12 @@ Adres: %4 Gebruik het testnetwerk - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepteer verbindingen van buitenaf (standaard: 1 als geen -proxy of -connect is opgegeven) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2334,11 +2327,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Kan geen lock op de datamap %s verkrijgen. Bitcoin draait vermoedelijk reeds. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Fout bij het initialiseren van database-omgeving %s! Om te herstellen, MAAK EEN BACKUP VAN DIE MAP, verwijder vervolgens alle bestanden in de map behalve wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2365,12 +2353,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Stel maximumgrootte in in bytes voor hoge-prioriteits-/lage-transactiekosten-transacties (standaard: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Stel het aantal threads in voor scriptverificatie (1-16, 0=auto, standaard: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Dit is een pre-release testversie - gebruik op eigen risico! Gebruik deze niet voor het delven van munten of handelsdoeleinden @@ -2410,7 +2393,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Blokcreatie-opties: - + Connect only to the specified node(s) Verbind alleen naar de gespecificeerde node(s) @@ -2430,7 +2413,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Wilt u de blokkendatabase nu herbouwen? - + Error initializing block database Fout bij intialisatie blokkendatabase @@ -2530,7 +2513,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Vind andere nodes d.m.v. DNS-naslag (standaard: 1 tenzij -connect) - + + Generate coins (default: 0) + Genereer munten (standaard: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Aantal te checken blokken bij het opstarten (standaard: 288, 0 = allemaal) @@ -2540,7 +2528,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Hoe grondig de blokverificatie is (0-4, standaard: 3) - + + Not enough file descriptors available. + Niet genoeg file descriptors beschikbaar. + + + Rebuild block chain index from current blk000??.dat files Blokketen opnieuw opbouwen van huidige blk000??.dat-bestanden @@ -2560,12 +2553,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Portomonnee aan het controleren... - + Imports blocks from external blk000??.dat file Importeert blokken van extern blk000??.dat bestand - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Stel het aantal threads voor scriptverificatie in (max 16, 0 = auto, <0 = laat zoveel cores vrij, standaard: 0) + + + Information Informatie @@ -2590,7 +2588,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Maximum per-connectie zendbuffer, <n>*1000 bytes (standaard: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Accepteer alleen blokketen die overeenkomt met de ingebouwde checkpoints (standaard: 1) @@ -2705,12 +2703,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Wachtwoord voor JSON-RPC-verbindingen - + Allow JSON-RPC connections from specified IP address Sta JSON-RPC verbindingen van opgegeven IP-adres toe - + Send commands to node running on <ip> (default: 127.0.0.1) Verstuur commando's naar proces dat op <ip> draait (standaard: 127.0.0.1) @@ -2750,12 +2748,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Geheime sleutel voor server (standaard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Aanvaardbare ciphers (standaard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Dit helpbericht @@ -2770,12 +2768,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verbind via een socks-proxy - + Allow DNS lookups for -addnode, -seednode and -connect Sta DNS-naslag toe voor -addnode, -seednode en -connect - + Loading addresses... Adressen aan het laden... @@ -2790,12 +2788,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Fout bij laden wallet.dat: Portemonnee vereist een nieuwere versie van Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Portemonnee moest herschreven worden: Herstart Bitcoin om te voltooien - + Error loading wallet.dat Fout bij laden wallet.dat @@ -2805,7 +2803,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ongeldig -proxy adres: '%s' - + Unknown network specified in -onlynet: '%s' Onbekend netwerk gespecificeerd in -onlynet: '%s' @@ -2825,7 +2823,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Kan -externlip adres niet herleiden: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ongeldig bedrag voor -paytxfee=<bedrag>: '%s' @@ -2845,7 +2843,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Blokindex aan het laden... - + Add a node to connect to and attempt to keep the connection open Voeg een node om naar te verbinden toe en probeer de verbinding open te houden @@ -2855,7 +2853,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Niet in staat om aan %s te binden op deze computer. Bitcoin draait vermoedelijk reeds. - + Fee per KB to add to transactions you send Kosten per KB om aan transacties toe te voegen die u verstuurt @@ -2865,15 +2863,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Portemonnee aan het laden... - + Cannot downgrade wallet Kan portemonnee niet downgraden - - - Cannot initialize keypool - Kan sleutel-pool niet initialiseren - Cannot write default address @@ -2885,22 +2878,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Blokketen aan het doorzoeken... - + Done loading Klaar met laden - + To use the %s option Om de %s optie te gebruiken - + Error Fout - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index cbe76f6e0..2b239c035 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -35,7 +35,7 @@ This product includes software developed by the OpenSSL Project for use in the O The Bitcoin developers - + Deweloperzy Bitcoin @@ -103,7 +103,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Export - + &Eksportuj @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Podpisz wiado&mość... - + Synchronizing with network... Synchronizacja z siecią... - + &Overview P&odsumowanie @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Zmień hasło... - + Importing blocks from disk... Importowanie bloków z dysku... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Ponowne indeksowanie bloków na dysku... - + Send coins to a Bitcoin address Wyślij monety na adres Bitcoin @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Zweryfikuj wiadomość... - - + + Bitcoin Bitcoin - + Wallet Portfel - + &Send Wyślij @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin klient - + %n active connection(s) to Bitcoin network %n aktywne połączenie do sieci Bitcoin%n aktywne połączenia do sieci Bitcoin%n aktywnych połączeń do sieci Bitcoin @@ -670,7 +670,7 @@ Adres: %4 Portfel jest <b>zaszyfrowany</b> i obecnie <b>zablokowany</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Błąd krytyczny. Bitcoin nie może kontynuować bezpiecznie więc zostanie zamknięty. @@ -809,8 +809,8 @@ Adres: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Opcjonalna prowizja za transakcje za kB, wspomaga ona szybkość przebiegu transakcji. Większość transakcji jest 1 kB. Zalecana prowizja 0.01 . + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -1650,7 +1650,7 @@ Adres: %4 The Bitcoin developers - + Deweloperzy Bitcoin @@ -2135,12 +2135,17 @@ Adres: %4 WalletView - + + &Export + &Eksportuj + + + Export the data in the current tab to a file Eksportuj dane z aktywnej karty do pliku - + Backup Wallet Kopia Zapasowa Portfela @@ -2173,12 +2178,12 @@ Adres: %4 bitcoin-core - + Bitcoin version Wersja Bitcoin - + Usage: Użycie: @@ -2188,7 +2193,7 @@ Adres: %4 Wyślij polecenie do -server lub bitcoind - + List commands Lista poleceń @@ -2198,7 +2203,7 @@ Adres: %4 Uzyskaj pomoc do polecenia - + Options: Opcje: @@ -2213,17 +2218,7 @@ Adres: %4 Wskaż plik pid (domyślnie: bitcoin.pid) - - Generate coins - Generuj monety - - - - Don't generate coins - Nie generuj monet - - - + Specify data directory Wskaż folder danych @@ -2233,7 +2228,7 @@ Adres: %4 Ustaw rozmiar w megabajtach cache-u bazy danych (domyślnie: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Nasłuchuj połączeń na <port> (domyślnie: 8333 lub testnet: 18333) @@ -2243,7 +2238,7 @@ Adres: %4 Utrzymuj maksymalnie <n> połączeń z peerami (domyślnie: 125) - + Connect to a node to retrieve peer addresses, and disconnect Podłącz się do węzła aby otrzymać adresy peerów i rozłącz @@ -2263,22 +2258,22 @@ Adres: %4 Czas w sekundach, przez jaki nietrzymający się zasad peerzy nie będą mogli ponownie się podłączyć (domyślnie: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Wystąpił błąd podczas ustawiania portu RPC %u w tryb nasłuchu: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Nasłuchuj połączeń JSON-RPC na <port> (domyślnie: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Akceptuj linię poleceń oraz polecenia JSON-RPC - + Run in the background as a daemon and accept commands Uruchom w tle jako daemon i przyjmuj polecenia @@ -2288,12 +2283,12 @@ Adres: %4 Użyj sieci testowej - + Accept connections from outside (default: 1 if no -proxy or -connect) Akceptuj połączenia z zewnątrz (domyślnie: 1 jeśli nie ustawiono -proxy lub -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2331,11 +2326,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Nie można zablokować folderu danych %s. Bitcoin prawdopodobnie już działa. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Błąd inicjowania środowiska bazy danych %s! Aby odtworzyć, ZACHOWAJ TEN KATALOG, po czym usuń z niego wszystko poza wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2362,12 +2352,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Ustaw maksymalny rozmiar transakcji o wysokim priorytecie/niskiej prowizji w bajtach (domyślnie: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Ustaw liczbę wątków weryfikacji skryptów (1-16, 0=auto, domyślnie: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2407,7 +2392,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Opcje tworzenia bloku: - + Connect only to the specified node(s) Łącz tylko do wskazanego węzła @@ -2427,7 +2412,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Czy chcesz teraz przebudować bazę bloków? - + Error initializing block database Błąd inicjowania bloku bazy danych @@ -2527,7 +2512,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Wyszukaj połączenia wykorzystując zapytanie DNS (domyślnie 1 jeśli nie użyto -connect) - + + Generate coins (default: 0) + Generuj monety (domyślnie: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Ile bloków sprawdzić przy starcie (domyślnie: 288, 0 = wszystkie) @@ -2537,7 +2527,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Jak dokładna jest weryfikacja bloku (0-4, domyślnie: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Odbuduj indeks łańcucha bloków z obecnych plików blk000??.dat @@ -2557,12 +2552,17 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Weryfikacja portfela... - + Imports blocks from external blk000??.dat file Importuj bloki z zewnętrznego pliku blk000??.dat - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Ustaw liczbę wątków skryptu weryfikacji (do 16, 0 = auto, <0 = zostawia taką ilość rdzenie wolnych, domyślnie: 0) + + + Information Informacja @@ -2587,7 +2587,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Maksymalny bufor wysyłu na połączenie, <n>*1000 bajtów (domyślnie: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Akceptuj tylko łańcuch bloków zgodny z wbudowanymi punktami kontrolnymi (domyślnie: 1) @@ -2702,12 +2702,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Hasło do połączeń JSON-RPC - + Allow JSON-RPC connections from specified IP address Przyjmuj połączenia JSON-RPC ze wskazanego adresu IP - + Send commands to node running on <ip> (default: 127.0.0.1) Wysyłaj polecenia do węzła działającego na <ip> (domyślnie: 127.0.0.1) @@ -2747,12 +2747,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Klucz prywatny serwera (domyślnie: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Aceptowalne szyfry (domyślnie: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ta wiadomość pomocy @@ -2767,12 +2767,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Łączy przez proxy socks - + Allow DNS lookups for -addnode, -seednode and -connect Zezwól -addnode, -seednode i -connect na łączenie się z serwerem DNS - + Loading addresses... Wczytywanie adresów... @@ -2787,12 +2787,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Błąd ładowania wallet.dat: Portfel wymaga nowszej wersji Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Portfel wymaga przepisania: zrestartuj Bitcoina żeby ukończyć - + Error loading wallet.dat Błąd ładowania wallet.dat @@ -2802,7 +2802,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nieprawidłowy adres -proxy: '%s' - + Unknown network specified in -onlynet: '%s' Nieznana sieć w -onlynet: '%s' @@ -2822,7 +2822,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nie można uzyskać adresu -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Nieprawidłowa kwota dla -paytxfee=<amount>: '%s' @@ -2842,7 +2842,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Ładowanie indeksu bloku... - + Add a node to connect to and attempt to keep the connection open Dodaj węzeł do łączenia się and attempt to keep the connection open @@ -2852,7 +2852,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nie można przywiązać %s na tym komputerze. Bitcoin prawdopodobnie już działa. - + Fee per KB to add to transactions you send @@ -2863,15 +2863,10 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Wczytywanie portfela... - + Cannot downgrade wallet Nie można dezaktualizować portfela - - - Cannot initialize keypool - Inicjalizacja puli kluczy nieudana - Cannot write default address @@ -2883,22 +2878,22 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Ponowne skanowanie... - + Done loading Wczytywanie zakończone - + To use the %s option Aby użyć opcji %s - + Error Błąd - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index de5751c4c..80681e8ca 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -323,17 +323,17 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS BitcoinGUI - + Sign &message... &Assinar Mensagem... - + Synchronizing with network... Sincronizando com a rede... - + &Overview &Visão geral @@ -408,7 +408,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS &Mudar frase de segurança... - + Importing blocks from disk... Importando blocos do disco... @@ -418,7 +418,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Reindexando blocos no disco... - + Send coins to a Bitcoin address Enviar moedas para um endereço bitcoin @@ -453,18 +453,18 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS &Verificar mensagem... - - + + Bitcoin Bitcoin - + Wallet Carteira - + &Send &Enviar @@ -540,7 +540,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS Cliente Bitcoin - + %n active connection(s) to Bitcoin network %n conexão ativa na rede Bitcoin%n conexões ativas na rede Bitcoin @@ -669,7 +669,7 @@ Endereço: %4 Carteira está <b>criptografada</b> e atualmente <b>bloqueada</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Um erro fatal ocorreu. Bitcoin não pode continuar em segurança e irá fechar. @@ -808,8 +808,8 @@ Endereço: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Taxa opcional de transações por kB que ajuda a garantir que suas transações serão processadas rapidamente. A maior parte das transações é de 1 kB. Taxa de 0.01 recomendada. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2134,12 +2134,17 @@ Endereço: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Exportar os dados na aba atual para um arquivo - + Backup Wallet Fazer cópia de segurança da Carteira @@ -2172,12 +2177,12 @@ Endereço: %4 bitcoin-core - + Bitcoin version Versão do Bitcoin - + Usage: Uso: @@ -2187,7 +2192,7 @@ Endereço: %4 Enviar comando para -server ou bitcoind - + List commands Lista de comandos @@ -2197,7 +2202,7 @@ Endereço: %4 Obtenha ajuda sobre um comando - + Options: Opções: @@ -2212,17 +2217,7 @@ Endereço: %4 Especifique um arquivo de pid (padrão: bitcoind.pid) - - Generate coins - Gerar bitcoins - - - - Don't generate coins - Não gerar bitcoins - - - + Specify data directory Especificar diretório de dados @@ -2232,7 +2227,7 @@ Endereço: %4 Definir o tamanho do cache do banco de dados em megabytes (padrão: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Procurar por conexões em <port> (padrão: 8333 ou testnet:18333) @@ -2242,7 +2237,7 @@ Endereço: %4 Manter no máximo <n> conexões aos peers (padrão: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conectar a um nó para receber endereços de participantes, e desconectar. @@ -2262,22 +2257,22 @@ Endereço: %4 Número de segundos para impedir que peers mal comportados reconectem (padrão: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Um erro ocorreu ao configurar a porta RPC %u para escuta em IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Escutar conexões JSON-RPC na porta <porta> (padrão: 8332 ou testnet: 18332) - + Accept command line and JSON-RPC commands Aceitar linha de comando e comandos JSON-RPC - + Run in the background as a daemon and accept commands Rodar em segundo plano como serviço e aceitar comandos @@ -2287,12 +2282,12 @@ Endereço: %4 Usar rede de teste - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceitar conexões externas (padrão: 1 se opções -proxy ou -connect não estiverem presentes) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2331,11 +2326,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Não foi possível obter exclusividade de escrita no endereço %s. O Bitcoin provavelmente já está rodando. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Erro ao inicializar o ambiente de banco de dados %s! Para recuperar: FAÇA BACKUP DAQUELE DIRETÓRIO, e então remova tudo dele, exceto o arquivo wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2362,12 +2352,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Determinar tamanho máximo de transações de alta-prioridade/baixa-taxa em bytes (padrão: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Definir número de threads de script de verificação (1-16, 0=auto, padrão: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Este pode ser um build de teste pré-lançamento - use por sua conta e risco - não use para mineração ou aplicações de comércio. @@ -2407,7 +2392,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Opções de criação de blocos: - + Connect only to the specified node(s) Conectar apenas a nó(s) específico(s) @@ -2427,7 +2412,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Você quer reconstruir o banco de dados de blocos agora? - + Error initializing block database Erro ao inicializar banco de dados de blocos @@ -2527,7 +2512,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Procurar pares usando consulta de DNS (padrão: 1 a menos que a opção -connect esteja presente) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Quantos blocos checar ao inicializar (padrão: 288, 0 = todos) @@ -2537,7 +2527,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Quão minuciosa é a verificação dos blocos (0-4, padrão: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Reconstruir índice de blockchain a partir dos arquivos atuais blk000??.dat @@ -2557,12 +2552,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verificando carteira... - + Imports blocks from external blk000??.dat file Importar blocos de um arquivo externo blk000??.dat - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Informação @@ -2587,7 +2587,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Buffer máximo de envio por conexão, <n>*1000 bytes (padrão: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Apenas aceitar cadeia de blocos correspondente a marcas de verificação internas (padrão: 1) @@ -2702,12 +2702,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Senha para conexões JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitir conexões JSON-RPC de endereços IP específicos - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comando para nó rodando em <ip> (pardão: 127.0.0.1) @@ -2747,12 +2747,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chave privada do servidor (padrão: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Algoritmos de criptografia aceitos (padrão: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Esta mensagem de ajuda @@ -2767,12 +2767,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Conectar através de um proxy socks - + Allow DNS lookups for -addnode, -seednode and -connect Permitir consultas DNS para -addnode, -seednode e -connect - + Loading addresses... Carregando endereços... @@ -2787,12 +2787,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Erro ao carregar wallet.dat: Carteira requer uma versão mais nova do Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete A Carteira precisou ser reescrita: reinicie o Bitcoin para completar - + Error loading wallet.dat Erro ao carregar wallet.dat @@ -2802,7 +2802,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Endereço -proxy inválido: '%s' - + Unknown network specified in -onlynet: '%s' Rede desconhecida especificada em -onlynet: '%s' @@ -2822,7 +2822,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossível encontrar endereço -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantidade inválida para -paytxfee=<quantidade>: '%s' @@ -2842,7 +2842,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Carregando índice de blocos... - + Add a node to connect to and attempt to keep the connection open Adicionar um nó com o qual se conectar e tentar manter a conexão ativa @@ -2852,7 +2852,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossível vincular a %s neste computador. O Bitcoin provavelmente já está rodando. - + Fee per KB to add to transactions you send Taxa por KB a ser acrescida nas transações que você enviar @@ -2862,15 +2862,10 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Carregando carteira... - + Cannot downgrade wallet Não é possível fazer downgrade da carteira - - - Cannot initialize keypool - Não foi possível inicializar o pool de chaves - Cannot write default address @@ -2882,22 +2877,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Re-escaneando... - + Done loading Carregamento terminado - + To use the %s option Para usar a opção %s - + Error Erro - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 593c4e9d1..c387ff9ab 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -10,7 +10,7 @@ <b>Bitcoin</b> version - <b>Bitcoin</b> versão + Versão do <b>Bitcoin</b> @@ -35,7 +35,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open The Bitcoin developers - + Os programadores Bitcoin @@ -103,7 +103,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open &Export - + &Exportar @@ -158,7 +158,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Could not write to file %1. - Não conseguiu escrever para o ficheiro %1. + Não foi possível escrever para o ficheiro %1. @@ -323,17 +323,17 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open BitcoinGUI - + Sign &message... Assinar &mensagem... - + Synchronizing with network... Sincronizando com a rede... - + &Overview Visã&o geral @@ -408,7 +408,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Mudar &Palavra-passe... - + Importing blocks from disk... Importando blocos do disco... @@ -418,7 +418,7 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Reindexando blocos no disco... - + Send coins to a Bitcoin address Enviar moedas para um endereço bitcoin @@ -453,18 +453,18 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open &Verificar mensagem... - - + + Bitcoin Bitcoin - + Wallet Carteira - + &Send &Enviar @@ -540,14 +540,14 @@ Este produto inclui software desenvolvido pelo Projecto OpenSSL para uso no Open Cliente Bitcoin - + %n active connection(s) to Bitcoin network %n ligação ativa à rede Bitcoin%n ligações ativas à rede Bitcoin No block source available... - + Nenhum bloco fonto disponível @@ -670,7 +670,7 @@ Endereço: %4 A carteira está <b>encriptada</b> e atualmente <b>bloqueada</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ocorreu um erro fatal. O Bitcoin não pode continuar com segurança e irá fechar. @@ -809,8 +809,8 @@ Endereço: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Taxa de transação opcional por KB que ajuda a assegurar que as suas transações serão processadas rapidamente. A maioria das transações tem 1 kB. Taxa de 0.01 recomendada. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Taxa de transação opcional por KB que ajuda a assegurar que as suas transações serão processadas rapidamente. A maioria das transações tem 1 kB. @@ -1650,7 +1650,7 @@ Endereço: %4 The Bitcoin developers - + Os programadores Bitcoin @@ -2135,12 +2135,17 @@ Endereço: %4 WalletView - + + &Export + &Exportar + + + Export the data in the current tab to a file Exportar os dados no separador actual para um ficheiro - + Backup Wallet Cópia de Segurança da Carteira @@ -2173,12 +2178,12 @@ Endereço: %4 bitcoin-core - + Bitcoin version Versão Bitcoin - + Usage: Utilização: @@ -2188,7 +2193,7 @@ Endereço: %4 Enviar comando para -server ou bitcoind - + List commands Listar comandos @@ -2198,7 +2203,7 @@ Endereço: %4 Obter ajuda para um comando - + Options: Opções: @@ -2213,17 +2218,7 @@ Endereço: %4 Especificar ficheiro pid (por defeito: bitcoind.pid) - - Generate coins - Gerar moedas - - - - Don't generate coins - Não gerar moedas - - - + Specify data directory Especificar pasta de dados @@ -2233,7 +2228,7 @@ Endereço: %4 Definir o tamanho da cache de base de dados em megabytes (por defeito: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Escute por ligações em <port> (por defeito: 8333 ou testnet: 18333) @@ -2243,7 +2238,7 @@ Endereço: %4 Manter no máximo <n> ligações a outros nós da rede (por defeito: 125) - + Connect to a node to retrieve peer addresses, and disconnect Ligar a um nó para recuperar endereços de pares, e desligar @@ -2263,22 +2258,22 @@ Endereço: %4 Número de segundos a impedir que nós mal-formados se liguem de novo (por defeito: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Ocorreu um erro ao definir a porta %u do serviço RPC a escutar em IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Escutar por ligações JSON-RPC em <port> (por defeito: 8332 ou rede de testes: 18332) - + Accept command line and JSON-RPC commands Aceitar comandos da consola e JSON-RPC - + Run in the background as a daemon and accept commands Correr o processo como um daemon e aceitar comandos @@ -2288,12 +2283,12 @@ Endereço: %4 Utilizar a rede de testes - testnet - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceitar ligações externas (padrão: 1 sem -proxy ou -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2332,11 +2327,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Impossível trancar a pasta de dados %s. Provavelmente o Bitcoin já está a ser executado. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Erro ao inicializar o ambiente de recuperação de base de dados %s! Para recuperar, COPIE A PASTA PARA OUTRO LOCAL, e então remova tudo de dentro dela excepto o ficheiro wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2363,12 +2353,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Definir tamanho máximo de transações de alta-/baixa-prioridade em bytes (por defeito: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Defina o número de processos de verificação (1-16, 0=auto, por defeito: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Esta é uma versão de pré-lançamento - use à sua responsabilidade - não usar para minar ou aplicações comerciais @@ -2408,7 +2393,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Opções de criação de bloco: - + Connect only to the specified node(s) Apenas ligar ao(s) nó(s) especificado(s) @@ -2428,7 +2413,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Deseja reconstruir agora a cadeia de blocos? - + Error initializing block database Erro ao inicializar a cadeia de blocos @@ -2528,7 +2513,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Encontrar pares usando procura DNS (por defeito: 1 excepto -connect) - + + Generate coins (default: 0) + Gerar moedas (por defeito: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Quantos blocos verificar ao começar (por defeito: 288, 0 = todos) @@ -2538,7 +2528,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Qual a minúcia na verificação de blocos (0-4, por defeito: 3) - + + Not enough file descriptors available. + Descritores de ficheiros disponíveis são insuficientes. + + + Rebuild block chain index from current blk000??.dat files Reconstruir a cadeia de blocos dos ficheiros blk000??.dat actuais @@ -2558,12 +2553,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Verificando a carteira... - + Imports blocks from external blk000??.dat file Importar blocos de um ficheiro blk000??.dat externo - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Defina o número de processos de verificação (até 16, 0 = automático, <0 = disponibiliza esse número de núcleos livres, por defeito: 0) + + + Information Informação @@ -2588,7 +2588,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Armazenamento intermédio de envio por ligação, <n>*1000 bytes (por defeito: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Apenas aceitar cadeia de blocos coincidente com marcas de verificação internas (por defeito: 1) @@ -2703,12 +2703,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Palavra-passe para ligações JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitir ligações JSON-RPC do endereço IP especificado - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comandos para o nó a correr em <ip> (por defeito: 127.0.0.1) @@ -2748,12 +2748,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Chave privada do servidor (por defeito: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifras aceitáveis (por defeito: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Esta mensagem de ajuda @@ -2768,12 +2768,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Ligar através de um proxy socks - + Allow DNS lookups for -addnode, -seednode and -connect Permitir procuras DNS para -addnode, -seednode e -connect - + Loading addresses... Carregar endereços... @@ -2788,12 +2788,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Erro ao carregar wallet.dat: A Carteira requer uma versão mais recente do Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete A Carteira precisou ser reescrita: reinicie o Bitcoin para completar - + Error loading wallet.dat Erro ao carregar wallet.dat @@ -2803,7 +2803,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Endereço -proxy inválido: '%s' - + Unknown network specified in -onlynet: '%s' Rede desconhecida especificada em -onlynet: '%s' @@ -2823,7 +2823,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Não conseguiu resolver endereço -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantia inválida para -paytxfee=<amount>: '%s' @@ -2843,7 +2843,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Carregar índice de blocos... - + Add a node to connect to and attempt to keep the connection open Adicione um nó ao qual se ligar e tentar manter a ligação aberta @@ -2853,7 +2853,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Incapaz de vincular à porta %s neste computador. Provavelmente o Bitcoin já está a funcionar. - + Fee per KB to add to transactions you send Taxa por KB a adicionar a transações enviadas @@ -2863,15 +2863,10 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Carregar carteira... - + Cannot downgrade wallet Impossível mudar a carteira para uma versão anterior - - - Cannot initialize keypool - Impossível inicializar keypool - Cannot write default address @@ -2883,22 +2878,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Reexaminando... - + Done loading Carregamento completo - + To use the %s option Para usar a opção %s - + Error Erro - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index 047cd48fe..db011784d 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Semneaza &mesaj... - + Synchronizing with network... Se sincronizează cu reţeaua... - + &Overview &Detalii @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Schimbă parola... - + Importing blocks from disk... Importare blocks de pe disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address &Trimiteţi Bitcoin către o anumită adresă @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O Verifica mesajul - - + + Bitcoin Bitcoin - + Wallet Portofelul - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O Client Bitcoin - + %n active connection(s) to Bitcoin network %n active connections to Bitcoin network%n active connections to Bitcoin network%n active connections to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 Portofelul electronic este <b>criptat</b> iar in momentul de faţă este <b>blocat</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,8 +800,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Taxa de tranzacție opțional pe kB, care vă ajută sa va asigurati că tranzacțiile sunt procesate rapid. Cele mai multe tranzacții sunt de la 1 kB. Taxa de 0.01 recomandat. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version versiunea Bitcoin - + Usage: Uz: @@ -2179,7 +2184,7 @@ Address: %4 Trimite comanda la -server sau bitcoind - + List commands Listă de comenzi @@ -2189,7 +2194,7 @@ Address: %4 Ajutor pentru o comandă - + Options: Setări: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - Generare monede - - - - Don't generate coins - Nu genera monede! - - - + Specify data directory Specifica datele directorului @@ -2224,7 +2219,7 @@ Address: %4 Seteaza marimea cache a bazei de date in MB (initial: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Lista a conectiunile in <port> (initial: 8333 sau testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 Se menține la cele mai multe conexiuni <n> cu colegii (implicit: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conecteaza-te la nod pentru a optine adresa peer, si deconecteaza-te @@ -2254,22 +2249,22 @@ Address: %4 Numărul de secunde pentru a păstra colegii funcționează corect la reconectare (implicit: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Se accepta command line si comenzi JSON-RPC - + Run in the background as a daemon and accept commands Ruleaza în background ca un demon și accepta comenzi. @@ -2279,13 +2274,13 @@ Address: %4 Utilizeaza test de retea - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepta conexiuni de la straini (initial: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2314,11 +2309,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2345,12 +2335,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Seteaza marimea maxima a tranzactie mare/mica in bytes (initial:27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2390,7 +2375,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Optiuni creare block - + Connect only to the specified node(s) Conecteaza-te doar la nod(urile) specifice @@ -2410,7 +2395,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2510,7 +2495,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2520,7 +2510,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2540,12 +2535,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2570,7 +2570,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2685,12 +2685,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Parola pentru conectiunile JSON-RPC - + Allow JSON-RPC connections from specified IP address Permiteti conectiunile JSON-RPC de la o adresa IP specifica. - + Send commands to node running on <ip> (default: 127.0.0.1) Trimite comenzi la nod, ruland pe ip-ul (initial: 127.0.0.1) @@ -2730,12 +2730,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cheia privata a serverului ( initial: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Accepta cifruri (initial: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Acest mesaj de ajutor. @@ -2752,12 +2752,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Conectează prin proxy SOCKS - + Allow DNS lookups for -addnode, -seednode and -connect Permite DNS-ului sa se uite dupa -addnode, -seednode si -connect - + Loading addresses... Încarc adrese... @@ -2772,12 +2772,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Eroare incarcare wallet.dat: Portofelul are nevoie de o versiune Bitcoin mai noua - + Wallet needed to be rewritten: restart Bitcoin to complete Portofelul trebuie rescris: restarteaza aplicatia bitcoin pentru a face asta. - + Error loading wallet.dat Eroare incarcand wallet.dat @@ -2787,7 +2787,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Adresa proxy invalida: '%s' - + Unknown network specified in -onlynet: '%s' Retea specificata necunoscuta -onlynet: '%s' @@ -2807,7 +2807,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nu se poate rezolva -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Suma invalida pentru -paytxfee=<amount>: '%s' @@ -2827,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Încarc indice bloc... - + Add a node to connect to and attempt to keep the connection open Add a node to connect to and attempt to keep the connection open details suggestions history @@ -2839,7 +2839,7 @@ details suggestions history Imposibilitatea de a lega la% s pe acest computer. Bitcoin este, probabil, deja în execuție. - + Fee per KB to add to transactions you send Taxa pe kb pentru a adauga tranzactii trimise @@ -2849,15 +2849,10 @@ details suggestions history Încarc portofel... - + Cannot downgrade wallet Nu se poate face downgrade la portofel - - - Cannot initialize keypool - Nu se poate initializa keypool - Cannot write default address @@ -2869,22 +2864,22 @@ details suggestions history Rescanez... - + Done loading Încărcare terminată - + To use the %s option Pentru a folosii optiunea %s - + Error Eroare - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index 192f98bc1..4a62472bf 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Подписать сообщение... - + Synchronizing with network... Синхронизация с сетью... - + &Overview О&бзор @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Изменить пароль... - + Importing blocks from disk... Импортируются блоки с диска... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Идёт переиндексация блоков на диске... - + Send coins to a Bitcoin address Отправить монеты на указанный адрес Bitcoin @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O &Проверить сообщение... - - + + Bitcoin Биткоин - + Wallet Бумажник - + &Send &Отправить @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin клиент - + %n active connection(s) to Bitcoin network %n активное соединение с сетью%n активных соединений с сетью%n активных соединений с сетью @@ -670,7 +670,7 @@ Address: %4 Бумажник <b>зашифрован</b> и в настоящее время <b>заблокирован</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Произошла неисправимая ошибка. Bitcoin не может безопасно продолжать работу и будет закрыт. @@ -809,8 +809,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Необязательная комиссия за каждый КБ транзакции, которая позволяет быть уверенным, что Ваша транзакция будет обработана быстро. Большинство транзакций занимают 1КБ. Рекомендуется комиссия 0.01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2135,12 +2135,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Экспортировать данные из вкладки в файл - + Backup Wallet Сделать резервную копию бумажника @@ -2173,12 +2178,12 @@ Address: %4 bitcoin-core - + Bitcoin version Версия - + Usage: Использование: @@ -2188,7 +2193,7 @@ Address: %4 Отправить команду на -server или bitcoind - + List commands Список команд @@ -2199,7 +2204,7 @@ Address: %4 Получить помощь по команде - + Options: Опции: @@ -2214,17 +2219,7 @@ Address: %4 Задать pid-файл (по умолчанию: bitcoin.pid) - - Generate coins - Генерировать монеты - - - - Don't generate coins - Не генерировать монеты - - - + Specify data directory Задать каталог данных @@ -2234,7 +2229,7 @@ Address: %4 Установить размер кэша базы данных в мегабайтах (по умолчанию: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Принимать входящие подключения на <port> (по умолчанию: 8333 или 18333 в тестовой сети) @@ -2244,7 +2239,7 @@ Address: %4 Поддерживать не более <n> подключений к узлам (по умолчанию: 125) - + Connect to a node to retrieve peer addresses, and disconnect Подключиться к узлу, чтобы получить список адресов других участников и отключиться @@ -2264,22 +2259,22 @@ Address: %4 Число секунд блокирования неправильно ведущих себя узлов (по умолчанию: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Произошла ошибка при открытии RPC-порта %u для прослушивания на IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Прослушивать подключения JSON-RPC на <порту> (по умолчанию: 8332 или для testnet: 18332) - + Accept command line and JSON-RPC commands Принимать командную строку и команды JSON-RPC - + Run in the background as a daemon and accept commands Запускаться в фоне как демон и принимать команды @@ -2289,12 +2284,12 @@ Address: %4 Использовать тестовую сеть - + Accept connections from outside (default: 1 if no -proxy or -connect) Принимать подключения извне (по умолчанию: 1, если не используется -proxy или -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2333,11 +2328,6 @@ rpcpassword=%s Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Не удаётся установить блокировку на каталог данных %s. Возможно, Bitcoin уже работает. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Ошибка инициализации окружения базы данных %s! Чтобы восстановить работоспособность, СДЕЛАЙТЕ РЕЗЕРВНУЮ КОПИЮ ЭТОГО КАТАЛОГА, после чего удалите из него всё, кроме wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2364,12 +2354,7 @@ rpcpassword=%s Максимальный размер высокоприоритетных/низкокомиссионных транзакций в байтах (по умолчанию: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Задать число потоков проверки скрипта (1-16, 0=авто, по умолчанию: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Это пре-релизная тестовая сборка - используйте на свой страх и риск - не используйте для добычи или торговых приложений @@ -2409,7 +2394,7 @@ rpcpassword=%s Параметры создания блоков: - + Connect only to the specified node(s) Подключаться только к указанному узлу(ам) @@ -2429,7 +2414,7 @@ rpcpassword=%s Пересобрать БД блоков прямо сейчас? - + Error initializing block database Ошибка инициализации БД блоков @@ -2529,7 +2514,12 @@ rpcpassword=%s Искать узлы с помощью DNS (по умолчанию: 1, если не указан -connect) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Сколько блоков проверять при запуске (по умолчанию: 288, 0 = все) @@ -2539,7 +2529,12 @@ rpcpassword=%s Насколько тщательно проверять блок (0-4, по умолчанию: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files Перестроить индекс цепи блоков из текущих файлов blk000??.dat @@ -2559,12 +2554,17 @@ rpcpassword=%s Проверка бумажника... - + Imports blocks from external blk000??.dat file Импортировать блоки из внешнего файла blk000??.dat - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Информация @@ -2589,7 +2589,7 @@ rpcpassword=%s Максимальный размер буфера отправки на соединение, <n>*1000 байт (по умолчанию: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Принимать цепь блоков, только если она соответствует встроенным контрольным точкам (по умолчанию: 1) @@ -2705,12 +2705,12 @@ rpcpassword=%s Пароль для подключений JSON-RPC - + Allow JSON-RPC connections from specified IP address Разрешить подключения JSON-RPC с указанного IP - + Send commands to node running on <ip> (default: 127.0.0.1) Посылать команды узлу, запущенному на <ip> (по умолчанию: 127.0.0.1) @@ -2750,12 +2750,12 @@ rpcpassword=%s Приватный ключ сервера (по умолчанию: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Разрешённые алгоритмы (по умолчанию: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Эта справка @@ -2770,12 +2770,12 @@ rpcpassword=%s Подключаться через socks прокси - + Allow DNS lookups for -addnode, -seednode and -connect Разрешить поиск в DNS для -addnode, -seednode и -connect - + Loading addresses... Загрузка адресов... @@ -2790,12 +2790,12 @@ rpcpassword=%s Ошибка загрузки wallet.dat: бумажник требует более новую версию Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Необходимо перезаписать бумажник, перезапустите Bitcoin для завершения операции. - + Error loading wallet.dat Ошибка при загрузке wallet.dat @@ -2805,7 +2805,7 @@ rpcpassword=%s Неверный адрес -proxy: '%s' - + Unknown network specified in -onlynet: '%s' В параметре -onlynet указана неизвестная сеть: '%s' @@ -2825,7 +2825,7 @@ rpcpassword=%s Не удаётся разрешить адрес в параметре -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Неверное количество в параметре -paytxfee=<кол-во>: '%s' @@ -2845,7 +2845,7 @@ rpcpassword=%s Загрузка индекса блоков... - + Add a node to connect to and attempt to keep the connection open Добавить узел для подключения и пытаться поддерживать соединение открытым @@ -2855,7 +2855,7 @@ rpcpassword=%s Невозможно привязаться к %s на этом компьютере. Возможно, Bitcoin уже работает. - + Fee per KB to add to transactions you send Комиссия на килобайт, добавляемая к вашим транзакциям @@ -2865,15 +2865,10 @@ rpcpassword=%s Загрузка бумажника... - + Cannot downgrade wallet Не удаётся понизить версию бумажника - - - Cannot initialize keypool - Не удаётся инициализировать массив ключей - Cannot write default address @@ -2885,22 +2880,22 @@ rpcpassword=%s Сканирование... - + Done loading Загрузка завершена - + To use the %s option Чтобы использовать опцию %s - + Error Ошибка - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index 5449ece98..e1c1c051c 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... Podpísať &správu... - + Synchronizing with network... Synchronizácia so sieťou... - + &Overview &Prehľad @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Zmena Hesla... - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address Poslať bitcoins na adresu @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet Peňaženka - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network %n aktívne spojenie v Bitcoin sieti%n aktívne spojenia v Bitcoin sieti%n aktívnych spojení v Bitconi sieti @@ -664,7 +664,7 @@ Adresa: %4 Peňaženka je <b>zašifrovaná</b> a momentálne <b>zamknutá</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -803,8 +803,8 @@ Adresa: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Voliteľný transakčný poplatok za kB ktorý pomôže rýchlemu spracovaniu transakcie. Väčšina transakcií má 1 kB. Poplatok 0.01 je odporúčaný. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2129,12 +2129,17 @@ Adresa: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Exportovať tento náhľad do súboru - + Backup Wallet @@ -2167,12 +2172,12 @@ Adresa: %4 bitcoin-core - + Bitcoin version Bitcoin verzia - + Usage: Použitie: @@ -2182,7 +2187,7 @@ Adresa: %4 Odoslať príkaz -server alebo bitcoind - + List commands Zoznam príkazov @@ -2192,7 +2197,7 @@ Adresa: %4 Dostať pomoc pre príkaz - + Options: Možnosti: @@ -2207,17 +2212,7 @@ Adresa: %4 Určiť súbor pid (predvolené: bitcoind.pid) - - Generate coins - Počítaj bitcoins - - - - Don't generate coins - Nepočítaj bitcoins - - - + Specify data directory Určiť priečinok s dátami @@ -2227,7 +2222,7 @@ Adresa: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) Načúvať spojeniam na <port> (prednastavené: 8333 alebo testovacia sieť: 18333) @@ -2237,7 +2232,7 @@ Adresa: %4 Udržiavať maximálne <n> spojení (predvolené: 125) - + Connect to a node to retrieve peer addresses, and disconnect @@ -2257,22 +2252,22 @@ Adresa: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Počúvať JSON-RPC spojeniam na <port> (predvolené: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Prijímať príkazy z príkazového riadku a JSON-RPC - + Run in the background as a daemon and accept commands Bežať na pozadí ako démon a prijímať príkazy @@ -2282,12 +2277,12 @@ Adresa: %4 Použiť testovaciu sieť - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2316,11 +2311,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2347,12 +2337,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2392,7 +2377,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) Pripojiť sa len k určenej nóde @@ -2412,7 +2397,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2512,7 +2497,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2522,7 +2512,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2542,12 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2572,7 +2572,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2687,12 +2687,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Heslo pre JSON-rPC spojenia - + Allow JSON-RPC connections from specified IP address Povoliť JSON-RPC spojenia z určenej IP adresy. - + Send commands to node running on <ip> (default: 127.0.0.1) Poslať príkaz nóde bežiacej na <ip> (predvolené: 127.0.0.1) @@ -2732,12 +2732,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Súkromný kľúč servra (predvolené: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Prijateľné šifry (predvolené: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Táto pomocná správa @@ -2752,12 +2752,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Pripojenie cez socks proxy - + Allow DNS lookups for -addnode, -seednode and -connect Povoliť vyhľadávanie DNS pre pridanie nódy a spojenie - + Loading addresses... Načítavanie adries... @@ -2772,12 +2772,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chyba načítania wallet.dat: Peňaženka vyžaduje novšiu verziu Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Bolo potrebné prepísať peňaženku: dokončite reštartovaním Bitcoin - + Error loading wallet.dat Chyba načítania wallet.dat @@ -2787,7 +2787,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Neplatná adresa proxy: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2807,7 +2807,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Neplatná suma pre -paytxfee=<amount>: '%s' @@ -2827,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Načítavanie zoznamu blokov... - + Add a node to connect to and attempt to keep the connection open Pridať nódu a pripojiť sa and attempt to keep the connection open @@ -2837,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send Poplatok za kB ktorý treba pridať k odoslanej transakcii @@ -2847,15 +2847,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Načítavam peňaženku... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2867,22 +2862,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading Dokončené načítavanie - + To use the %s option - + Error Chyba - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 17de8d72c..ecb3342ac 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... Синхронизација са мрежом у току... - + &Overview &Општи преглед @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O Промени &лозинку... - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address Пошаљите новац на bitcoin адресу @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet новчаник - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network %n активна веза са Bitcoin мрежом%n активне везе са Bitcoin мрежом%n активних веза са Bitcoin мрежом @@ -661,7 +661,7 @@ Address: %4 Новчаник јс <b>шифрован</b> и тренутно <b>закључан</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version Bitcoin верзија - + Usage: Korišćenje: @@ -2180,7 +2185,7 @@ Address: %4 - + List commands Listaj komande @@ -2190,7 +2195,7 @@ Address: %4 Zatraži pomoć za komande - + Options: Opcije @@ -2205,17 +2210,7 @@ Address: %4 Konkretizuj pid fajl (podrazumevani: bitcoind.pid) - - Generate coins - Generiši novčiće - - - - Don't generate coins - Ne generiši novčiće - - - + Specify data directory Gde je konkretni data direktorijum @@ -2225,7 +2220,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) Slušaj konekcije na <port> (default: 8333 or testnet: 18333) @@ -2236,7 +2231,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2256,22 +2251,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands Prihvati komandnu liniju i JSON-RPC komande - + Run in the background as a daemon and accept commands Radi u pozadini kao daemon servis i prihvati komande @@ -2281,12 +2276,12 @@ Address: %4 Koristi testnu mrežu - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2315,11 +2310,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2346,12 +2336,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2391,7 +2376,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2411,7 +2396,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2511,7 +2496,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2521,7 +2511,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2541,12 +2536,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2571,7 +2571,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2686,12 +2686,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Lozinka za JSON-RPC konekcije - + Allow JSON-RPC connections from specified IP address Dozvoli JSON-RPC konekcije sa posebne IP adrese - + Send commands to node running on <ip> (default: 127.0.0.1) Pošalji komande to nodu koji radi na <ip> (default: 127.0.0.1) @@ -2731,12 +2731,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. privatni ključ za Server (podrazumevan: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Prihvatljive cifre (podrazumevano: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ova poruka Pomoći @@ -2751,12 +2751,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... učitavam adrese.... @@ -2771,12 +2771,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2786,7 +2786,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2806,7 +2806,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2826,7 +2826,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Učitavam blok indeksa... - + Add a node to connect to and attempt to keep the connection open @@ -2836,7 +2836,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2846,15 +2846,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Новчаник се учитава... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2866,22 +2861,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ponovo skeniram... - + Done loading Završeno učitavanje - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 119f7b6ef..f57ce9699 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -324,17 +324,17 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni BitcoinGUI - + Sign &message... Signera &meddelande... - + Synchronizing with network... Synkroniserar med nätverk... - + &Overview &Översikt @@ -409,7 +409,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni &Byt Lösenord... - + Importing blocks from disk... Importerar block från disk... @@ -419,7 +419,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Återindexerar block på disken... - + Send coins to a Bitcoin address Skicka mynt till en Bitcoin-adress @@ -454,18 +454,18 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni &Verifiera meddelande... - - + + Bitcoin Bitcoin - + Wallet Plånbok - + &Send &Skicka @@ -541,7 +541,7 @@ Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användni Bitcoin-klient - + %n active connection(s) to Bitcoin network %n aktiv anslutning till Bitcoin-nätverket%n aktiva anslutningar till Bitcoin-nätverket @@ -671,7 +671,7 @@ Adress: %4 Denna plånbok är <b>krypterad</b> och för närvarande <b>låst</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ett allvarligt fel har uppstått. Bitcoin kan inte längre köras säkert och kommer att avslutas. @@ -810,8 +810,8 @@ Adress: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Valfri transaktionsavgift per kB som ser till att dina transaktioner behandlas snabbt. De flesta transaktioner är 1 kB. Avgift 0.01 rekommenderas. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Valfri transaktionsavgift per kB som ser till att dina transaktioner behandlas snabbt. De flesta transaktioner är 1 kB. @@ -2136,12 +2136,17 @@ Adress: %4 WalletView - + + &Export + &Exportera + + + Export the data in the current tab to a file Exportera informationen i den nuvarande fliken till en fil - + Backup Wallet Säkerhetskopiera Plånbok @@ -2174,12 +2179,12 @@ Adress: %4 bitcoin-core - + Bitcoin version Bitcoin version - + Usage: Användning: @@ -2189,7 +2194,7 @@ Adress: %4 Skicka kommando till -server eller bitcoind - + List commands Lista kommandon @@ -2199,7 +2204,7 @@ Adress: %4 Få hjälp med ett kommando - + Options: Inställningar: @@ -2214,17 +2219,7 @@ Adress: %4 Ange pid fil (förvalt: bitcoind.pid) - - Generate coins - Generera mynt - - - - Don't generate coins - Generera inte mynt - - - + Specify data directory Ange katalog för data @@ -2234,7 +2229,7 @@ Adress: %4 Sätt databas cache storleken i megabyte (förvalt: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Lyssna efter anslutningar på <port> (förvalt: 8333 eller testnet: 18333) @@ -2244,7 +2239,7 @@ Adress: %4 Ha som mest <n> anslutningar till andra klienter (förvalt: 125) - + Connect to a node to retrieve peer addresses, and disconnect Anslut till en nod för att hämta klientadresser, och koppla från @@ -2264,22 +2259,22 @@ Adress: %4 Antal sekunder att hindra klienter som missköter sig från att ansluta (förvalt: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s Ett fel uppstod vid upprättandet av RPC port %u för att lyssna på IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Lyssna på JSON-RPC-anslutningar på <port> (förvalt: 8332 eller testnet: 18332) - + Accept command line and JSON-RPC commands Tillåt kommandon från kommandotolken och JSON-RPC-kommandon - + Run in the background as a daemon and accept commands Kör i bakgrunden som tjänst och acceptera kommandon @@ -2289,12 +2284,12 @@ Adress: %4 Använd testnätverket - + Accept connections from outside (default: 1 if no -proxy or -connect) Acceptera anslutningar utifrån (förvalt: 1 om ingen -proxy eller -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2333,11 +2328,6 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Cannot obtain a lock on data directory %s. Bitcoin is probably already running. Kan inte låsa data-mappen %s. Bitcoin körs förmodligen redan. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - Fel vid initiering databasmiljön %s! För att återställa, SÄKERHETSKOPIERA KATALOGEN, därefter ta bort allt från det utom wallet.dat. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2364,12 +2354,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Sätt den maximala storleken av hög-prioriterade/låg-avgifts transaktioner i byte (förvalt: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Ange antalet skriptkontrolltrådar (1-16, 0 = auto, förval: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Detta är ett förhands testbygge - använd på egen risk - använd inte för mining eller handels applikationer @@ -2409,7 +2394,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Block skapande inställningar: - + Connect only to the specified node(s) Koppla enbart upp till den/de specificerade noden/noder @@ -2429,7 +2414,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Vill du bygga om blockdatabasen nu? - + Error initializing block database Fel vid initiering av blockdatabasen @@ -2529,7 +2514,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Sök efter klienter med DNS sökningen (förvalt: 1 om inte -connect) - + + Generate coins (default: 0) + Generera mynt (förvalt: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Hur många block att kontrollera vid uppstart (standardvärde: 288, 0 = alla) @@ -2539,7 +2529,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Hur grundlig blockverifikationen är (0-4, förvalt: 3) - + + Not enough file descriptors available. + Inte tillräckligt med filbeskrivningar tillgängliga. + + + Rebuild block chain index from current blk000??.dat files Återskapa blockkedjans index från nuvarande blk000??.dat filer @@ -2559,12 +2554,17 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Verifierar plånboken... - + Imports blocks from external blk000??.dat file Importerar block från extern blk000??.dat fil - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Ange antalet skriptkontrolltrådar (upp till 16, 0 = auto, <0 = lämna så många kärnor lediga, förval: 0) + + + Information Information @@ -2589,7 +2589,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Maximal buffert för sändning per anslutning, <n>*1000 byte (förvalt: 5000) - + Only accept block chain matching built-in checkpoints (default: 1) Acceptera bara blockkedjans matchande inbyggda kontrollpunkter (förvalt: 1) @@ -2704,12 +2704,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Lösenord för JSON-RPC-anslutningar - + Allow JSON-RPC connections from specified IP address Tillåt JSON-RPC-anslutningar från specifika IP-adresser - + Send commands to node running on <ip> (default: 127.0.0.1) Skicka kommandon till klient på <ip> (förvalt: 127.0.0.1) @@ -2749,12 +2749,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Serverns privata nyckel (förvalt: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Accepterade krypteringsalgoritmer (förvalt: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Det här hjälp medelandet @@ -2769,12 +2769,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Anslut genom socks-proxy - + Allow DNS lookups for -addnode, -seednode and -connect Tillåt DNS-sökningar för -addnode, -seednode och -connect - + Loading addresses... Laddar adresser... @@ -2789,12 +2789,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Fel vid inläsningen av wallet.dat: Plånboken kräver en senare version av Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Plånboken behöver skrivas om: Starta om Bitcoin för att färdigställa - + Error loading wallet.dat Fel vid inläsning av plånboksfilen wallet.dat @@ -2804,7 +2804,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Ogiltig -proxy adress: '%s' - + Unknown network specified in -onlynet: '%s' Okänt nätverk som anges i -onlynet: '%s' @@ -2824,7 +2824,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Kan inte matcha -externalip adress: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ogiltigt belopp för -paytxfee=<belopp>:'%s' @@ -2844,7 +2844,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Laddar blockindex... - + Add a node to connect to and attempt to keep the connection open Lägg till en nod att koppla upp mot och försök att hålla anslutningen öppen @@ -2854,7 +2854,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Det går inte att binda till %s på den här datorn. Bitcoin är förmodligen redan igång. - + Fee per KB to add to transactions you send Avgift per KB att lägga till på transaktioner du skickar @@ -2864,15 +2864,10 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Laddar plånbok... - + Cannot downgrade wallet Kan inte nedgradera plånboken - - - Cannot initialize keypool - Kan inte initiera keypool - Cannot write default address @@ -2884,22 +2879,22 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Söker igen... - + Done loading Klar med laddning - + To use the %s option Att använda %s alternativet - + Error Fel - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index 0557e4700..ad220f14a 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -318,17 +318,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... - + Synchronizing with network... - + &Overview @@ -403,7 +403,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Importing blocks from disk... @@ -413,7 +413,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address @@ -448,18 +448,18 @@ This product includes software developed by the OpenSSL Project for use in the O - - + + Bitcoin - + Wallet - + &Send @@ -535,7 +535,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + %n active connection(s) to Bitcoin network @@ -661,7 +661,7 @@ Address: %4 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -800,7 +800,7 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. @@ -2126,12 +2126,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file - + Backup Wallet @@ -2164,12 +2169,12 @@ Address: %4 bitcoin-core - + Bitcoin version - + Usage: @@ -2179,7 +2184,7 @@ Address: %4 - + List commands @@ -2189,7 +2194,7 @@ Address: %4 - + Options: @@ -2204,17 +2209,7 @@ Address: %4 - - Generate coins - - - - - Don't generate coins - - - - + Specify data directory @@ -2224,7 +2219,7 @@ Address: %4 - + Listen for connections on <port> (default: 8333 or testnet: 18333) @@ -2234,7 +2229,7 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect @@ -2254,22 +2249,22 @@ Address: %4 - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) - + Accept command line and JSON-RPC commands - + Run in the background as a daemon and accept commands @@ -2279,12 +2274,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2313,11 +2308,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2344,12 +2334,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2389,7 +2374,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) @@ -2409,7 +2394,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database @@ -2509,7 +2494,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) @@ -2519,7 +2509,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2539,12 +2534,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information @@ -2569,7 +2569,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2684,12 +2684,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) @@ -2729,12 +2729,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message @@ -2749,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... @@ -2769,12 +2769,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat @@ -2784,7 +2784,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Unknown network specified in -onlynet: '%s' @@ -2804,7 +2804,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2824,7 +2824,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Add a node to connect to and attempt to keep the connection open @@ -2834,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send @@ -2844,15 +2844,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2864,22 +2859,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Done loading - + To use the %s option - + Error - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index 0563ca7c8..ec83848fb 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Mesaj imzala... - + Synchronizing with network... Şebeke ile senkronizasyon... - + &Overview &Genel bakış @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O Parolayı &değiştir... - + Importing blocks from disk... Bloklar diskten içe aktarılıyor... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O Diskteki bloklar yeniden endeksleniyor... - + Send coins to a Bitcoin address Bir Bitcoin adresine Bitcoin yolla @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O Mesaj &kontrol et... - - + + Bitcoin Bitcoin - + Wallet Cüzdan - + &Send &Gönder @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin istemcisi - + %n active connection(s) to Bitcoin network Bitcoin şebekesine %n faal bağlantıBitcoin şebekesine %n faal bağlantı @@ -670,7 +670,7 @@ Adres: %4 Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilitlidir</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. Ciddi bir hata oluştu. Bitcoin artık güvenli bir şekilde işlemeye devam edemez ve kapanacaktır. @@ -809,8 +809,8 @@ Adres: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Muamelelerin hızlı işlenmesini garantilemeye yardım eden, seçime dayalı kB başı muamele ücreti. Muamelelerin çoğunluğunun boyutu 1 kB'dir. 0.01 ücreti tavsiye edilir. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + Muamelelerin hızlı işlenmesini garantilemeye yardım eden, seçime dayalı kB başı muamele ücreti. Muamelelerin çoğunluğunun boyutu 1 kB'dir. @@ -2135,12 +2135,17 @@ Adres: %4 WalletView - + + &Export + &Dışa aktar + + + Export the data in the current tab to a file Güncel sekmedeki verileri bir dosyaya aktar - + Backup Wallet Cüzdanı yedekle @@ -2173,12 +2178,12 @@ Adres: %4 bitcoin-core - + Bitcoin version Bitcoin sürümü - + Usage: Kullanım: @@ -2188,7 +2193,7 @@ Adres: %4 -server ya da bitcoind'ye komut gönder - + List commands Komutları listele @@ -2198,7 +2203,7 @@ Adres: %4 Bir komut için yardım al - + Options: Seçenekler: @@ -2213,17 +2218,7 @@ Adres: %4 Pid dosyası belirt (varsayılan: bitcoind.pid) - - Generate coins - Madenî para (Bitcoin) oluştur - - - - Don't generate coins - Bitcoin oluşturmasını devre dışı bırak - - - + Specify data directory Veri dizinini belirt @@ -2233,7 +2228,7 @@ Adres: %4 Veritabanı önbellek boyutunu megabayt olarak belirt (varsayılan: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Bağlantılar için dinlenecek <port> (varsayılan: 8333 ya da testnet: 18333) @@ -2243,7 +2238,7 @@ Adres: %4 Eşler ile en çok <n> adet bağlantı kur (varsayılan: 125) - + Connect to a node to retrieve peer addresses, and disconnect Eş adresleri elde etmek için bir düğüme bağlan ve ardından bağlantıyı kes @@ -2263,22 +2258,22 @@ Adres: %4 Aksaklık gösteren eşlerle yeni bağlantıları engelleme süresi, saniye olarak (varsayılan: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s IPv4 üzerinde dinlemek için %u numaralı RPC portunun kurulumu sırasında hata meydana geldi: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) JSON-RPC bağlantılarını <port> üzerinde dinle (varsayılan: 8332 veya tesnet: 18332) - + Accept command line and JSON-RPC commands Konut satırı ve JSON-RPC komutlarını kabul et - + Run in the background as a daemon and accept commands Arka planda daemon (servis) olarak çalış ve komutları kabul et @@ -2288,12 +2283,12 @@ Adres: %4 Deneme şebekesini kullan - + Accept connections from outside (default: 1 if no -proxy or -connect) Dışarıdan gelen bağlantıları kabul et (varsayılan: -proxy veya -connect yoksa 1) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2332,11 +2327,6 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Cannot obtain a lock on data directory %s. Bitcoin is probably already running. %s veri dizininde kilit elde edilemedi. Bitcoin muhtemelen hâlihazırda çalışmaktadır. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - %s veritabanı ortamının başlatılması sırasında bir hata meydana geldi! Düzeltmek için BU KLASÖRÜ YEDEKLEYİN, ardından klasörden wallet.dat dışında tüm dosyaları silin. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2363,12 +2353,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Yüksek öncelikli/düşük ücretli muamelelerin boyutunu bayt olarak tanımla (varsayılan: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - Betik kontrolü iş parçacığı sayısını belirt (1 ilâ 6, 0=otomatik, varsayılan: 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications Bu yayın öncesi bir deneme sürümüdür - tüm riski siz üstlenmiş olursunuz - bitcoin oluşturmak ya da ticari uygulamalar için kullanmayınız @@ -2408,7 +2393,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blok oluşturma seçenekleri: - + Connect only to the specified node(s) Sadece belirtilen düğüme veya düğümlere bağlan @@ -2428,7 +2413,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blok veritabanını şimdi yeniden inşa etmek istiyor musunuz? - + Error initializing block database Blok veritabanını başlatılırken bir hata meydana geldi @@ -2528,7 +2513,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Eşleri DNS araması vasıtasıyla bul (varsayılan: 1, eğer -connect kullanılmadıysa) - + + Generate coins (default: 0) + Bitcoin oluştur (varsayılan: 0) + + + How many blocks to check at startup (default: 288, 0 = all) Başlangıçta kontrol edilecek blok sayısı (varsayılan: 288, 0 = hepsi) @@ -2538,7 +2528,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blok kontrolünün ne kadar derin olacağı (0 ilâ 4, varsayılan: 3) - + + Not enough file descriptors available. + Kafi derecede dosya tanımlayıcıları mevcut değil. + + + Rebuild block chain index from current blk000??.dat files Blok zinciri indeksini güncel blk000??.dat dosyalarından tekrar inşa et @@ -2558,12 +2553,17 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Cüzdan kontrol ediliyor... - + Imports blocks from external blk000??.dat file Harici blk000??.dat dosyasından blokları içe aktarır - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + Betik kontrolü iş parçacığı sayısını belirt (azami 16, 0 = otomatik, <0 = bu sayıda çekirdeği boş bırak, varsayılan: 0) + + + Information Bilgi @@ -2588,7 +2588,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Bağlantı başına azami yollama tamponu, <n>*1000 bayt (varsayılan: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) Sadece yerleşik kontrol noktalarıyla eşleşen blok zincirini kabul et (varsayılan: 1) @@ -2703,12 +2703,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com JSON-RPC bağlantıları için parola - + Allow JSON-RPC connections from specified IP address Belirtilen İP adresinden JSON-RPC bağlantılarını kabul et - + Send commands to node running on <ip> (default: 127.0.0.1) Şu <ip> adresinde (varsayılan: 127.0.0.1) çalışan düğüme komut yolla @@ -2748,12 +2748,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Sunucu özel anahtarı (varsayılan: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Kabul edilebilir şifreler (varsayılan: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Bu yardım mesajı @@ -2768,12 +2768,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Socks vekil sunucusu vasıtasıyla bağlan - + Allow DNS lookups for -addnode, -seednode and -connect -addnode, -seednode ve -connect için DNS aramalarına izin ver - + Loading addresses... Adresler yükleniyor... @@ -2788,12 +2788,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com wallet.dat dosyasının yüklenmesinde hata oluştu: cüzdanın daha yeni bir Bitcoin sürümüne ihtiyacı var - + Wallet needed to be rewritten: restart Bitcoin to complete Cüzdanın tekrar yazılması gerekiyordu: işlemi tamamlamak için Bitcoin'i yeniden başlatınız - + Error loading wallet.dat wallet.dat dosyasının yüklenmesinde hata oluştu @@ -2803,7 +2803,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Geçersiz -proxy adresi: '%s' - + Unknown network specified in -onlynet: '%s' -onlynet için bilinmeyen bir şebeke belirtildi: '%s' @@ -2823,7 +2823,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com -externalip adresi çözümlenemedi: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<miktar> için geçersiz miktar: '%s' @@ -2843,7 +2843,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blok indeksi yükleniyor... - + Add a node to connect to and attempt to keep the connection open Bağlanılacak düğüm ekle ve bağlantıyı zinde tutmaya çalış @@ -2853,7 +2853,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Bu bilgisayarda %s unsuruna bağlanılamadı. Bitcoin muhtemelen hâlihazırda çalışmaktadır. - + Fee per KB to add to transactions you send Yolladığınız muameleler için eklenecek KB başı ücret @@ -2863,15 +2863,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Cüzdan yükleniyor... - + Cannot downgrade wallet Cüzdan eski biçime geri alınamaz - - - Cannot initialize keypool - Keypool başlatılamadı - Cannot write default address @@ -2883,22 +2878,22 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Yeniden tarama... - + Done loading Yükleme tamamlandı - + To use the %s option %s seçeneğini kullanmak için - + Error Hata - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index c59c2a2f8..63faf67ec 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... &Підписати повідомлення... - + Synchronizing with network... Синхронізація з мережею... - + &Overview &Огляд @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O Змінити парол&ь... - + Importing blocks from disk... Імпорт блоків з диску... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O - + Send coins to a Bitcoin address Відправити монети на вказану адресу @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O Перевірити повідомлення... - - + + Bitcoin Bitcoin - + Wallet Гаманець - + &Send @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin-клієнт - + %n active connection(s) to Bitcoin network %n активне з'єднання з мережею%n активні з'єднання з мережею%n активних з'єднань з мережею @@ -670,7 +670,7 @@ Address: %4 <b>Зашифрований</b> гаманець <b>заблоковано</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. @@ -809,8 +809,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - Добровільна комісія за кожен КБ транзакції, яка дозволяє бути впевненим у тому, що ваш вона буде оброблено швидко. Розмір більшості транзакцій є 1 КБ. Рекомендована комісія: 0,01. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2135,12 +2135,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file Експортувати дані з поточної вкладки в файл - + Backup Wallet @@ -2173,12 +2178,12 @@ Address: %4 bitcoin-core - + Bitcoin version Версія - + Usage: Використання: @@ -2188,7 +2193,7 @@ Address: %4 Відправити команду серверу -server чи демону - + List commands Список команд @@ -2198,7 +2203,7 @@ Address: %4 Отримати довідку по команді - + Options: Параметри: @@ -2213,17 +2218,7 @@ Address: %4 Вкажіть pid-файл (типово: bitcoind.pid) - - Generate coins - Генерувати монети - - - - Don't generate coins - Не генерувати монети - - - + Specify data directory Вкажіть робочий каталог @@ -2233,7 +2228,7 @@ Address: %4 Встановити розмір кешу бази даних в мегабайтах (типово: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) Чекати на з'єднання на <port> (типово: 8333 або тестова мережа: 18333) @@ -2243,7 +2238,7 @@ Address: %4 Підтримувати не більше <n> зв'язків з колегами (типово: 125) - + Connect to a node to retrieve peer addresses, and disconnect @@ -2263,22 +2258,22 @@ Address: %4 Максимальній розмір вхідного буферу на одне з'єднання (типово: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) Прослуховувати <port> для JSON-RPC-з'єднань (типово: 8332 або тестова мережа: 18332) - + Accept command line and JSON-RPC commands Приймати команди із командного рядка та команди JSON-RPC - + Run in the background as a daemon and accept commands Запустити в фоновому режимі (як демон) та приймати команди @@ -2288,12 +2283,12 @@ Address: %4 Використовувати тестову мережу - + Accept connections from outside (default: 1 if no -proxy or -connect) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2322,11 +2317,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2353,12 +2343,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - - Set the number of script verification threads (1-16, 0=auto, default: 0) - - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications @@ -2398,7 +2383,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Connect only to the specified node(s) Підключитись лише до вказаного вузла @@ -2418,7 +2403,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Error initializing block database Помилка ініціалізації бази даних блоків @@ -2518,7 +2503,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) Скільки блоків перевіряти під час запуску (типово: 288, 0 = всі) @@ -2528,7 +2518,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files @@ -2548,12 +2543,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file Імпорт блоків з зовнішнього файлу blk000??.dat - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information Інформація @@ -2578,7 +2578,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Максимальній розмір вихідного буферу на одне з'єднання, <n>*1000 байт (типово: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) @@ -2693,12 +2693,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Пароль для JSON-RPC-з'єднань - + Allow JSON-RPC connections from specified IP address Дозволити JSON-RPC-з'єднання з вказаної IP-адреси - + Send commands to node running on <ip> (default: 127.0.0.1) Відправляти команди на вузол, запущений на <ip> (типово: 127.0.0.1) @@ -2738,12 +2738,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Закритий ключ сервера (типово: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Допустимі шифри (типово: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Дана довідка @@ -2758,12 +2758,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Підключитись через SOCKS-проксі - + Allow DNS lookups for -addnode, -seednode and -connect Дозволити пошук в DNS для команд -addnode, -seednode та -connect - + Loading addresses... Завантаження адрес... @@ -2778,12 +2778,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Помилка при завантаженні wallet.dat: Гаманець потребує новішої версії Біткоін-клієнта - + Wallet needed to be rewritten: restart Bitcoin to complete Потрібно перезаписати гаманець: перезапустіть Біткоін-клієнт для завершення - + Error loading wallet.dat Помилка при завантаженні wallet.dat @@ -2793,7 +2793,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Помилка в адресі проксі-сервера: «%s» - + Unknown network specified in -onlynet: '%s' Невідома мережа вказана в -onlynet: «%s» @@ -2813,7 +2813,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Помилка у величині комісії -paytxfee=<amount>: «%s» @@ -2833,7 +2833,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Завантаження індексу блоків... - + Add a node to connect to and attempt to keep the connection open Додати вузол до підключення і лишити його відкритим @@ -2843,7 +2843,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Неможливо прив'язати до порту %s на цьому комп'ютері. Можливо гаманець вже запущено. - + Fee per KB to add to transactions you send Комісія за КБ @@ -2853,15 +2853,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Завантаження гаманця... - + Cannot downgrade wallet - - - Cannot initialize keypool - - Cannot write default address @@ -2873,22 +2868,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Сканування... - + Done loading Завантаження завершене - + To use the %s option - + Error Помилка - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 3b5067e38..163b6ddaa 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... 对&消息签名... - + Synchronizing with network... 正在与网络同步... - + &Overview &概况 @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O &修改密码... - + Importing blocks from disk... 正在从磁盘导入数据块... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O 正在为数据块建立索引... - + Send coins to a Bitcoin address 向一个比特币地址发送比特币 @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O &验证消息... - - + + Bitcoin 比特币 - + Wallet 钱包 - + &Send &发送 @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O 比特币客户端 - + %n active connection(s) to Bitcoin network 到比特币网络的连接共有%n条 @@ -670,7 +670,7 @@ Address: %4 钱包已被<b>加密</b>,当前为<b>锁定</b>状态 - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. 发生严重错误。 @@ -810,8 +810,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - 建议支付交易费用,有助于您的交易得到尽快处理. 绝大多数交易的字节数为 1 kB. 建议支付0.01个比特币. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2136,12 +2136,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file 导出当前数据到文件 - + Backup Wallet 备份钱包 @@ -2174,12 +2179,12 @@ Address: %4 bitcoin-core - + Bitcoin version 比特币版本 - + Usage: 使用: @@ -2190,7 +2195,7 @@ Address: %4 - + List commands 列出命令 @@ -2202,7 +2207,7 @@ Address: %4 - + Options: 选项: @@ -2220,19 +2225,7 @@ Address: %4 - - Generate coins - 生成货币 - - - - - Don't generate coins - 不要生成货币 - - - - + Specify data directory 指定数据目录 @@ -2243,7 +2236,7 @@ Address: %4 设置数据库缓冲区大小 (缺省: 25MB) - + Listen for connections on <port> (default: 8333 or testnet: 18333) 监听端口连接 <port> (缺省: 8333 or testnet: 18333) @@ -2253,7 +2246,7 @@ Address: %4 最大连接数 <n> (缺省: 125) - + Connect to a node to retrieve peer addresses, and disconnect 连接一个节点并获取对端地址, 然后断开连接 @@ -2273,23 +2266,23 @@ Address: %4 Number of seconds to keep misbehaving peers from reconnecting (缺省: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s 设置RPC监听端口%u时发生错误, IPv4:%s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) JSON-RPC连接监听端口<port> (缺省:8332 testnet:18332) - + Accept command line and JSON-RPC commands 接受命令行和 JSON-RPC 命令 - + Run in the background as a daemon and accept commands 在后台运行并接受命令 @@ -2302,12 +2295,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) 接受来自外部的连接 (缺省: 如果不带 -proxy or -connect 参数设置为1) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2346,11 +2339,6 @@ rpcpassword=%s Cannot obtain a lock on data directory %s. Bitcoin is probably already running. 无法给数据目录 %s上锁。本软件可能已经在运行。 - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - 数据库环境%s初始化失败!恢复方法:备份该目录,然后删掉除wallet.dat之外的所有文件。 - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2377,12 +2365,7 @@ rpcpassword=%s Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - 设置Script验证进程数(1-16,0=自动,缺省:0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications 这是测试用的预发布版本 - 请谨慎使用 - 不要用来挖矿,或者在正式商用环境下使用 @@ -2422,7 +2405,7 @@ rpcpassword=%s 数据块创建选项: - + Connect only to the specified node(s) 仅连接到指定节点 @@ -2442,7 +2425,7 @@ rpcpassword=%s 你想现在就重建块数据库吗? - + Error initializing block database 初始化数据块数据库出错 @@ -2542,7 +2525,12 @@ rpcpassword=%s 通过DNS查找节点(缺省:1 除非使用 -connect 选项) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) 启动时检测多少个数据块(缺省:288,0=所有) @@ -2552,7 +2540,12 @@ rpcpassword=%s How thorough the block verification is (0-4, default: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files 重新为当前的blk000??.dat文件建立索引 @@ -2572,12 +2565,17 @@ rpcpassword=%s 正在检测钱包的完整性... - + Imports blocks from external blk000??.dat file 从blk000??.dat文件导入数据块 - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information 信息 @@ -2602,7 +2600,7 @@ rpcpassword=%s 每个连接的最大发送缓存,<n>*1000 字节(缺省:1000) - + Only accept block chain matching built-in checkpoints (default: 1) 仅接受符合客户端检查点设置的数据块文件 @@ -2719,13 +2717,13 @@ rpcpassword=%s - + Allow JSON-RPC connections from specified IP address 允许从指定IP接受到的JSON-RPC连接 - + Send commands to node running on <ip> (default: 127.0.0.1) 向IP地址为 <ip> 的节点发送指令 (缺省: 127.0.0.1) @@ -2770,13 +2768,13 @@ rpcpassword=%s - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) 可接受的加密器 (默认为 TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message 该帮助信息 @@ -2792,12 +2790,12 @@ rpcpassword=%s 通过 socks 代理连接 - + Allow DNS lookups for -addnode, -seednode and -connect 使用 -addnode, -seednode 和 -connect选项时允许DNS查找 - + Loading addresses... 正在加载地址... @@ -2812,12 +2810,12 @@ rpcpassword=%s wallet.dat钱包文件加载错误:请升级到最新Bitcoin客户端 - + Wallet needed to be rewritten: restart Bitcoin to complete 钱包文件需要重写:请退出并重新启动Bitcoin客户端 - + Error loading wallet.dat wallet.dat钱包文件加载错误 @@ -2827,7 +2825,7 @@ rpcpassword=%s 非法的代理地址: '%s' - + Unknown network specified in -onlynet: '%s' 被指定的是未知网络 -onlynet: '%s' @@ -2847,7 +2845,7 @@ rpcpassword=%s 无法解析 -externalip 地址: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' 非法金额 -paytxfee=<amount>: '%s' @@ -2867,7 +2865,7 @@ rpcpassword=%s 加载数据块索引... - + Add a node to connect to and attempt to keep the connection open 添加节点并与其保持连接 @@ -2877,7 +2875,7 @@ rpcpassword=%s 无法在本机绑定 %s 端口 . 比特币客户端软件可能已经在运行. - + Fee per KB to add to transactions you send 每发送1KB交易所需的费用 @@ -2887,15 +2885,10 @@ rpcpassword=%s 正在加载钱包... - + Cannot downgrade wallet 无法降级钱包格式 - - - Cannot initialize keypool - 无法初始化 keypool - Cannot write default address @@ -2907,22 +2900,22 @@ rpcpassword=%s 正在重新扫描... - + Done loading 加载完成 - + To use the %s option 使用 %s 选项 - + Error 错误 - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 7ccd5462d..c98cd6a53 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -323,17 +323,17 @@ This product includes software developed by the OpenSSL Project for use in the O BitcoinGUI - + Sign &message... 訊息簽署... - + Synchronizing with network... 網路同步中... - + &Overview 總覽 @@ -408,7 +408,7 @@ This product includes software developed by the OpenSSL Project for use in the O 密碼變更... - + Importing blocks from disk... 從磁碟匯入區塊中... @@ -418,7 +418,7 @@ This product includes software developed by the OpenSSL Project for use in the O 重建磁碟區塊索引中... - + Send coins to a Bitcoin address 付錢到位元幣位址 @@ -453,18 +453,18 @@ This product includes software developed by the OpenSSL Project for use in the O 驗證訊息... - - + + Bitcoin 位元幣 - + Wallet 錢包 - + &Send 付出 @@ -540,7 +540,7 @@ This product includes software developed by the OpenSSL Project for use in the O 位元幣客戶端軟體 - + %n active connection(s) to Bitcoin network 與位元幣網路有 %n 個連線在使用中 @@ -669,7 +669,7 @@ Address: %4 錢包<b>已加密</b>並且正<b>上鎖中</b> - + A fatal error occurred. Bitcoin can no longer continue safely and will quit. 發生了致命的錯誤. 位元幣程式無法再繼續安全執行, 只好結束. @@ -809,8 +809,8 @@ Address: %4 - Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. - 非必要的交易手續費, 以 kB 為計費單位, 且有助於縮短你的交易處理時間. 大部份交易的資料大小是 1 kB. 建議設定為 0.01 元. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + @@ -2135,12 +2135,17 @@ Address: %4 WalletView - + + &Export + + + + Export the data in the current tab to a file 將目前分頁的資料匯出存成檔案 - + Backup Wallet 錢包備份 @@ -2173,12 +2178,12 @@ Address: %4 bitcoin-core - + Bitcoin version 位元幣版本 - + Usage: 用法: @@ -2189,7 +2194,7 @@ Address: %4 - + List commands 列出指令 @@ -2201,7 +2206,7 @@ Address: %4 - + Options: 選項: @@ -2219,19 +2224,7 @@ Address: %4 - - Generate coins - 生產位元幣 - - - - - Don't generate coins - 不生產位元幣 - - - - + Specify data directory 指定資料目錄 @@ -2242,7 +2235,7 @@ Address: %4 設定資料庫快取大小為多少百萬位元組(MB, 預設: 25) - + Listen for connections on <port> (default: 8333 or testnet: 18333) 在通訊埠 <port> 聽候連線 (預設: 8333, 或若為測試網路: 18333) @@ -2252,7 +2245,7 @@ Address: %4 維持與節點連線數的上限為 <n> 個 (預設: 125) - + Connect to a node to retrieve peer addresses, and disconnect 連線到某個節點以取得其它節點的位址, 然後斷線 @@ -2272,23 +2265,23 @@ Address: %4 避免與亂搞的節點連線的秒數 (預設: 86400) - + An error occurred while setting up the RPC port %u for listening on IPv4: %s 在 IPv4 網路上以通訊埠 %u 聽取 RPC 連線時發生錯誤: %s - + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) 在通訊埠 <port> 聽候 JSON-RPC 連線 (預設: 8332, 或若為測試網路: 18332) - + Accept command line and JSON-RPC commands 接受命令列與 JSON-RPC 指令 - + Run in the background as a daemon and accept commands 以背景程式執行並接受指令 @@ -2299,12 +2292,12 @@ Address: %4 - + Accept connections from outside (default: 1 if no -proxy or -connect) 是否接受外來連線 (預設: 當沒有 -proxy 或 -connect 時預設為 1) - + %s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2344,11 +2337,6 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Cannot obtain a lock on data directory %s. Bitcoin is probably already running. 無法鎖定資料目錄 %s. 也許位元幣已經在執行了. - - - Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. - 資料庫環境 %s 初始化失敗了! 要復原資料, 請*務必先備份該資料夾*, 然後將其中除了錢包檔 wallet.dat 外的東西都刪除掉. - Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. @@ -2375,12 +2363,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 設定高優先權或低手續費的交易資料大小上限為多少位元組 (預設: 27000) - - Set the number of script verification threads (1-16, 0=auto, default: 0) - 設定指令碼驗證的執行緒數目 (1 至 16, 0 表示程式自動決定, 預設為 0) - - - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications 這是尚未發表的測試版本 - 使用請自負風險 - 請不要用於開採或商業應用 @@ -2420,7 +2403,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 區塊產生選項: - + Connect only to the specified node(s) 只連線至指定節點(可多個) @@ -2440,7 +2423,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 你要現在重建區塊資料庫嗎? - + Error initializing block database 初始化區塊資料庫失敗 @@ -2540,7 +2523,12 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 是否允許在找節點時使用域名查詢 (預設: 當沒用 -connect 時為 1) - + + Generate coins (default: 0) + + + + How many blocks to check at startup (default: 288, 0 = all) 啓動時檢查的區塊數 (預設: 288, 指定 0 表示全部) @@ -2550,7 +2538,12 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 區塊檢查的仔細程度 (0 至 4, 預設: 3) - + + Not enough file descriptors available. + + + + Rebuild block chain index from current blk000??.dat files 從目前的區塊檔 blk000??.dat 重建鎖鏈索引 @@ -2570,12 +2563,17 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 驗證錢包資料中... - + Imports blocks from external blk000??.dat file 從其它來源的 blk000??.dat 檔匯入區塊 - + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + Information 資訊 @@ -2600,7 +2598,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 每個連線的傳送緩衝區大小上限為 <n>*1000 位元組 (預設: 1000) - + Only accept block chain matching built-in checkpoints (default: 1) 只接受與內建的檢查段點吻合的區塊鎖鏈 (預設: 1) @@ -2715,12 +2713,12 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com JSON-RPC 連線密碼 - + Allow JSON-RPC connections from specified IP address 只允許從指定網路位址來的 JSON-RPC 連線 - + Send commands to node running on <ip> (default: 127.0.0.1) 送指令給在 <ip> 的節點 (預設: 127.0.0.1) @@ -2765,13 +2763,13 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) 可以接受的加密法 (預設: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message 此協助訊息 @@ -2787,12 +2785,12 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 透過 SOCKS 代理伺服器連線 - + Allow DNS lookups for -addnode, -seednode and -connect 允許對 -addnode, -seednode, -connect 的參數使用域名查詢 - + Loading addresses... 載入位址中... @@ -2807,12 +2805,12 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 載入檔案 wallet.dat 失敗: 此錢包需要新版的 Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete 錢包需要重寫: 請重啟位元幣來完成 - + Error loading wallet.dat 載入檔案 wallet.dat 失敗 @@ -2822,7 +2820,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無效的 -proxy 位址: '%s' - + Unknown network specified in -onlynet: '%s' 在 -onlynet 指定了不明的網路別: '%s' @@ -2842,7 +2840,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無法解析 -externalip 位址: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' 設定 -paytxfee=<金額> 的金額無效: '%s' @@ -2862,7 +2860,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 載入區塊索引中... - + Add a node to connect to and attempt to keep the connection open 加入一個要連線的節線, 並試著保持對它的連線暢通 @@ -2872,7 +2870,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無法和這台電腦上的 %s 繫結. 也許位元幣已經在執行了. - + Fee per KB to add to transactions you send 交易付款時每 KB 的交易手續費 @@ -2882,15 +2880,10 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 載入錢包中... - + Cannot downgrade wallet 無法將錢包格式降級 - - - Cannot initialize keypool - 無法將密鑰池初始化 - Cannot write default address @@ -2902,22 +2895,22 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 重新掃描中... - + Done loading 載入完成 - + To use the %s option 為了要使用 %s 選項 - + Error 錯誤 - + You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. From 92f2c1fe0fe2905540b0435188988851145f92be Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Tue, 7 May 2013 10:47:00 -0400 Subject: [PATCH 29/69] Use boost::asio::deadline_timer for walletpassphrase timeout New method in bitcoinrpc: RunLater, that uses a map of deadline timers to run a function later. Behavior of walletpassphrase is changed; before, calling walletpassphrase again before the lock timeout passed would result in: Error: Wallet is already unlocked. You would have to call lockwallet before walletpassphrase. Now: the last walletpassphrase with correct password wins, and overrides any previous timeout. Fixes issue# 1961 which was caused by spawning too many threads. Test plan: Start with encrypted wallet, password 'foo' NOTE: python -c 'import time; print("%d"%time.time())' ... will tell you current unix timestamp. Try: walletpassphrase foo 600 getinfo EXPECT: unlocked_until is about 10 minutes in the future walletpassphrase foo 1 sleep 2 sendtoaddress mun74Bvba3B1PF2YkrF4NsgcJwHXXh12LF 11 EXPECT: Error: Please enter the wallet passphrase with walletpassphrase first. walletpassphrase foo 600 walletpassphrase foo 0 getinfo EXPECT: wallet is locked (unlocked_until is 0) walletpassphrase foo 10 walletpassphrase foo 600 getinfo EXPECT: wallet is unlocked until 10 minutes in future walletpassphrase foo 60 walletpassphrase bar 600 EXPECT: Error, incorrect passphrase getinfo EXPECT: wallet still scheduled to lock 60 seconds from first (successful) walletpassphrase --- src/bitcoinrpc.cpp | 28 ++++++++++++++++--- src/bitcoinrpc.h | 6 +++++ src/rpcwallet.cpp | 67 ++++++++-------------------------------------- src/wallet.cpp | 5 +--- 4 files changed, 43 insertions(+), 63 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index a9b73fd5a..a1d76e181 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -11,17 +11,17 @@ #include "bitcoinrpc.h" #include "db.h" +#include #include #include +#include #include #include +#include #include #include #include -#include #include -#include -#include #include #include @@ -34,6 +34,7 @@ static std::string strRPCUserColonPass; // These are created by StartRPCThreads, destroyed in StopRPCThreads static asio::io_service* rpc_io_service = NULL; +static map > deadlineTimers; static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; @@ -843,6 +844,7 @@ void StopRPCThreads() { if (rpc_io_service == NULL) return; + deadlineTimers.clear(); rpc_io_service->stop(); rpc_worker_group->join_all(); delete rpc_worker_group; rpc_worker_group = NULL; @@ -850,6 +852,26 @@ void StopRPCThreads() delete rpc_io_service; rpc_io_service = NULL; } +void RPCRunHandler(const boost::system::error_code& err, boost::function func) +{ + if (!err) + func(); +} + +void RPCRunLater(const std::string& name, boost::function func, int64 nSeconds) +{ + assert(rpc_io_service != NULL); + + if (deadlineTimers.count(name) == 0) + { + deadlineTimers.insert(make_pair(name, + boost::shared_ptr(new deadline_timer(*rpc_io_service)))); + } + deadlineTimers[name]->expires_from_now(posix_time::seconds(nSeconds)); + deadlineTimers[name]->async_wait(boost::bind(RPCRunHandler, _1, func)); +} + + class JSONRequest { public: diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 315fd9238..270c2a009 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -88,6 +88,12 @@ void RPCTypeCheck(const json_spirit::Array& params, void RPCTypeCheck(const json_spirit::Object& o, const std::map& typesExpected, bool fAllowNull=false); +/* + Run func nSeconds from now. Uses boost deadline timers. + Overrides previous timer (if any). + */ +void RPCRunLater(const std::string& name, boost::function func, int64 nSeconds); + typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); class CRPCCommand diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 5fd400c6b..f304f7026 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -84,7 +84,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); + obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } @@ -1256,56 +1256,11 @@ Value keypoolrefill(const Array& params, bool fHelp) } -void ThreadTopUpKeyPool(void* parg) +static void LockWallet(CWallet* pWallet) { - // Make this thread recognisable as the key-topping-up thread - RenameThread("bitcoin-key-top"); - - pwalletMain->TopUpKeyPool(); -} - -void ThreadCleanWalletPassphrase(void* parg) -{ - // Make this thread recognisable as the wallet relocking thread - RenameThread("bitcoin-lock-wa"); - - int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000; - - ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - - if (nWalletUnlockTime == 0) - { - nWalletUnlockTime = nMyWakeTime; - - do - { - if (nWalletUnlockTime==0) - break; - int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); - if (nToSleep <= 0) - break; - - LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); - MilliSleep(nToSleep); - ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - - } while(1); - - if (nWalletUnlockTime) - { - nWalletUnlockTime = 0; - pwalletMain->Lock(); - } - } - else - { - if (nWalletUnlockTime < nMyWakeTime) - nWalletUnlockTime = nMyWakeTime; - } - - LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); - - delete (int64*)parg; + LOCK(cs_nWalletUnlockTime); + nWalletUnlockTime = 0; + pWallet->Lock(); } Value walletpassphrase(const Array& params, bool fHelp) @@ -1319,9 +1274,6 @@ Value walletpassphrase(const Array& params, bool fHelp) if (!pwalletMain->IsCrypted()) throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); - if (!pwalletMain->IsLocked()) - throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked."); - // Note that the walletpassphrase is stored in params[0] which is not mlock()ed SecureString strWalletPass; strWalletPass.reserve(100); @@ -1339,9 +1291,12 @@ Value walletpassphrase(const Array& params, bool fHelp) "walletpassphrase \n" "Stores the wallet decryption key in memory for seconds."); - NewThread(ThreadTopUpKeyPool, NULL); - int64* pnSleepTime = new int64(params[1].get_int64()); - NewThread(ThreadCleanWalletPassphrase, pnSleepTime); + pwalletMain->TopUpKeyPool(); + + int64 nSleepTime = params[1].get_int64(); + LOCK(cs_nWalletUnlockTime); + nWalletUnlockTime = GetTime() + nSleepTime; + RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime); return Value::null; } diff --git a/src/wallet.cpp b/src/wallet.cpp index c70ea20e8..eebd8ac18 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -87,9 +87,6 @@ bool CWallet::AddCScript(const CScript& redeemScript) bool CWallet::Unlock(const SecureString& strWalletPassphrase) { - if (!IsLocked()) - return false; - CCrypter crypter; CKeyingMaterial vMasterKey; @@ -100,7 +97,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) - return false; + continue; // try another master key if (CCryptoKeyStore::Unlock(vMasterKey)) return true; } From 5fdd1251a87a0938f48e88970ae976e360c6e09f Mon Sep 17 00:00:00 2001 From: William Yager Date: Tue, 7 May 2013 20:03:17 -0500 Subject: [PATCH 30/69] Specified base_uint component size A base_uint used to be made of an array of unsigned ints. This works fine on most platforms, but might not work on certain present or future platforms. The code breaks if an unsigned int is 16 or 64 bits, so it's important to be specific. Also changed "u" to "you". --- src/uint256.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/uint256.h b/src/uint256.h index 8a9af8ba0..2a252c94f 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -20,14 +21,14 @@ inline int Testuint256AdHoc(std::vector vArg); /** Base class without constructors for uint256 and uint160. - * This makes the compiler let u use it in a union. + * This makes the compiler let you use it in a union. */ template class base_uint { protected: enum { WIDTH=BITS/32 }; - unsigned int pn[WIDTH]; + uint32_t pn[WIDTH]; public: bool operator!() const From 40c387e517bba93f931c5dc4c85e0f117c166548 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Wed, 8 May 2013 08:43:20 +0200 Subject: [PATCH 31/69] translations update 2013-05-08 - integrates current translations from Transifex --- src/qt/locale/bitcoin_ar.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_bg.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_bs.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_ca.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_ca_ES.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_cs.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_cy.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_da.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_de.ts | 141 +++++++++++++++++++------------ src/qt/locale/bitcoin_el_GR.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_eo.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_es.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_es_CL.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_et.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_eu_ES.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_fa.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_fa_IR.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_fi.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_fr.ts | 143 +++++++++++++++++++------------ src/qt/locale/bitcoin_fr_CA.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_gu_IN.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_he.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_hi_IN.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_hr.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_hu.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_it.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_ja.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_la.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_lt.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_lv_LV.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_nb.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_nl.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_pl.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_pt_BR.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_pt_PT.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_ro_RO.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_ru.ts | 149 ++++++++++++++++++++------------- src/qt/locale/bitcoin_sk.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_sr.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_sv.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_th_TH.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_tr.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_uk.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_zh_CN.ts | 139 ++++++++++++++++++------------ src/qt/locale/bitcoin_zh_TW.ts | 147 +++++++++++++++++++------------- 45 files changed, 3882 insertions(+), 2397 deletions(-) diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 8c7e3c57c..028080d54 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index f0d1ff6b7..a55030565 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -2128,6 +2128,14 @@ Address: %4 до + + WalletModel + + + Send Coins + Изпращане + + WalletView @@ -2179,12 +2187,12 @@ Address: %4 Биткоин версия - + Usage: - + Send command to -server or bitcoind @@ -2194,17 +2202,17 @@ Address: %4 - + Get help for a command - + Options: Опции: - + Specify configuration file (default: bitcoin.conf) @@ -2219,7 +2227,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2234,12 +2242,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2249,7 +2257,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2269,17 +2277,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2423,11 +2431,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2514,7 +2517,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2529,7 +2532,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2539,17 +2542,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2558,6 +2561,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Невалиден -tor адрес: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2633,6 +2646,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2644,7 +2662,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2684,32 +2717,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2719,12 +2752,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2734,22 +2767,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2759,12 +2792,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... Зареждане на адресите... - + Error loading wallet.dat: Wallet corrupted @@ -2774,22 +2807,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' Невалиден -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2799,7 +2832,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2809,7 +2842,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2819,17 +2852,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... Зареждане на блок индекса... - + Add a node to connect to and attempt to keep the connection open @@ -2839,17 +2872,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... Зареждане на портфейла... - + Cannot downgrade wallet @@ -2859,22 +2892,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... Преразглеждане на последовтелността от блокове... - + Done loading Зареждането е завършено - + To use the %s option - + Error Грешка diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 3bddc0527..e1d54d1b7 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 1cd781d5c..8272324a8 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index a9d40f4a0..90dfc28e8 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -2123,6 +2123,14 @@ Address: %4 a + + WalletModel + + + Send Coins + Enviar monedes + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 Versió de Bitcoin - + Usage: Ús: - + Send command to -server or bitcoind Enviar comanda a -servidor o bitcoind @@ -2189,17 +2197,17 @@ Address: %4 Llista d'ordres - + Get help for a command Obtenir ajuda per a un ordre. - + Options: Opcions: - + Specify configuration file (default: bitcoin.conf) Especificat arxiu de configuració (per defecte: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 Especificar directori de dades - + Set database cache size in megabytes (default: 25) Establir tamany de la memoria cau en megabytes (per defecte: 25) @@ -2229,12 +2237,12 @@ Address: %4 Mantenir com a molt <n> connexions a peers (per defecte: 125) - + Connect to a node to retrieve peer addresses, and disconnect Connectar al node per obtenir les adreces de les connexions, i desconectar - + Specify your own public address Especificar la teva adreça pública @@ -2244,7 +2252,7 @@ Address: %4 Límit per a desconectar connexions errònies (per defecte: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Nombre de segons abans de reconectar amb connexions errònies (per defecte: 86400) @@ -2264,17 +2272,17 @@ Address: %4 Acceptar línia d'ordres i ordres JSON-RPC - + Run in the background as a daemon and accept commands Executar en segon pla com a programa dimoni i acceptar ordres - + Use the test network Usar la xarxa de prova - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceptar connexions d'afora (per defecte: 1 si no -proxy o -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Error: Espai al disc baix! - - - Error: Transaction creation failed! - Error: La ceació de la transacció ha fallat! - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Com verificar el bloc (0-4, per defecte 3) - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Estableix el nombre de fils per atendre trucades RPC (per defecte: 4) - + Verifying blocks... Verificant blocs... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verificant moneder... - + Imports blocks from external blk000??.dat file Importa blocs de un fitxer blk000??.dat extern - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information &Informació @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Adreça -tor invàlida: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Reduir l'arxiu debug.log al iniciar el client (per defecte 1 quan no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error de sistema: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Utilitza UPnP per a mapejar els ports d'escolta (per defecte: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. L'arxiu wallet.data és corrupte, el rescat de les dades ha fallat - + Password for JSON-RPC connections Contrasenya per a connexions JSON-RPC - + Allow JSON-RPC connections from specified IP address Permetre connexions JSON-RPC d'adreces IP específiques - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar ordre al node en execució a <ip> (per defecte: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Executar orde quan el millor bloc canviï (%s al cmd es reemplaça per un bloc de hash) - + Upgrade wallet to latest format Actualitzar moneder a l'últim format - + Set key pool size to <n> (default: 100) Establir límit de nombre de claus a <n> (per defecte: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Re-escanejar cadena de blocs en cerca de transaccions de moneder perdudes - + Use OpenSSL (https) for JSON-RPC connections Utilitzar OpenSSL (https) per a connexions JSON-RPC - + Server certificate file (default: server.cert) Arxiu del certificat de servidor (per defecte: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Clau privada del servidor (per defecte: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Xifrats acceptats (per defecte: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Aquest misatge d'ajuda - + Unable to bind to %s on this computer (bind returned error %d, %s) Impossible d'unir %s a aquest ordinador (s'ha retornat l'error %d, %s) - + Connect through socks proxy Connectar a través de socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Permetre consultes DNS per a -addnode, -seednode i -connect - + Loading addresses... Carregant adreces... - + Error loading wallet.dat: Wallet corrupted Error carregant wallet.dat: Moneder corrupte @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error carregant wallet.dat: El moneder requereix una versió de Bitcoin més moderna - + Wallet needed to be rewritten: restart Bitcoin to complete El moneder necesita ser re-escrit: re-inicia Bitcoin per a completar la tasca - + Error loading wallet.dat Error carregant wallet.dat - + Invalid -proxy address: '%s' Adreça -proxy invalida: '%s' - + Unknown network specified in -onlynet: '%s' Xarxa desconeguda especificada a -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. S'ha demanat una versió desconeguda de -socks proxy: %i - + Cannot resolve -bind address: '%s' No es pot resoldre l'adreça -bind: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es pot resoldre l'adreça -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantitat invalida per a -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Quanitat invalida - + Insufficient funds Balanç insuficient - + Loading block index... Carregant índex de blocs... - + Add a node to connect to and attempt to keep the connection open Afegir un node per a connectar's-hi i intentar mantenir la connexió oberta @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossible d'unir %s en aquest ordinador. Probablement Bitcoin ja estigui en execució. - + Fee per KB to add to transactions you send Comisió a afegir per cada KB de transaccions que enviïs - + Loading wallet... Carregant moneder... - + Cannot downgrade wallet No es pot reduir la versió del moneder @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es pot escriure l'adreça per defecte - + Rescanning... Re-escanejant... - + Done loading Càrrega acabada - + To use the %s option Utilitza la opció %s - + Error Error diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 03713fd02..8380ec637 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -2132,6 +2132,14 @@ Adresa: %4 + + WalletModel + + + Send Coins + Pošli mince + + WalletView @@ -2183,12 +2191,12 @@ Adresa: %4 Verze Bitcoinu - + Usage: Užití: - + Send command to -server or bitcoind Poslat příkaz pro -server nebo bitcoind @@ -2198,17 +2206,17 @@ Adresa: %4 Výpis příkazů - + Get help for a command Získat nápovědu pro příkaz - + Options: Možnosti: - + Specify configuration file (default: bitcoin.conf) Konfigurační soubor (výchozí: bitcoin.conf) @@ -2223,7 +2231,7 @@ Adresa: %4 Adresář pro data - + Set database cache size in megabytes (default: 25) Nastavit velikost databázové vyrovnávací paměti v megabajtech (výchozí: 25) @@ -2238,12 +2246,12 @@ Adresa: %4 Povolit nejvýše <n> připojení k uzlům (výchozí: 125) - + Connect to a node to retrieve peer addresses, and disconnect Připojit se k uzlu, získat adresy jeho protějšků a odpojit se - + Specify your own public address Specifikuj svou veřejnou adresu @@ -2253,7 +2261,7 @@ Adresa: %4 Práh pro odpojování zlobivých uzlů (výchozí: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Doba ve vteřinách, po kterou se nebudou moci zlobivé uzly znovu připojit (výchozí: 86400) @@ -2273,17 +2281,17 @@ Adresa: %4 Akceptovat příkazy z příkazové řádky a přes JSON-RPC - + Run in the background as a daemon and accept commands Běžet na pozadí jako démon a akceptovat příkazy - + Use the test network Použít testovací síť (testnet) - + Accept connections from outside (default: 1 if no -proxy or -connect) Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect) @@ -2437,11 +2445,6 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Problém: Na disku je málo místa! - - - Error: Transaction creation failed! - Chyba: Vytvoření transakce selhalo! - Error: Wallet locked, unable to create transaction! @@ -2528,7 +2531,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Jak moc důkladná má být verifikace bloků (0-4, výchozí: 3) - + Not enough file descriptors available. Je nedostatek deskriptorů souborů. @@ -2543,7 +2546,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nastavení počtu vláken pro servisní RPC volání (výchozí: 4) - + Verifying blocks... Ověřuji bloky... @@ -2553,17 +2556,17 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Kontroluji peněženku... - + Imports blocks from external blk000??.dat file Importovat bloky z externího souboru blk000??.dat - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Nastavení počtu vláken pro verifikaci skriptů (max. 16, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: 0) - + Information Informace @@ -2572,6 +2575,16 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Neplatná -tor adresa: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Neplatná částka pro -minrelaytxfee=<částka>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Neplatná částka pro -mintxfee=<částka>: '%s' + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Při spuštění klienta zmenšit soubor debug.log (výchozí: 1, pokud není zadáno -debug) + + + Signing transaction failed + Podepisování transakce selhalo + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Systémová chyba: - + + Transaction amount too small + Částka v transakci je příliš malá + + + + Transaction amounts must be positive + Částky v transakci musí být kladné + + + + Transaction too large + Transace je příliš velká + + + Use UPnP to map the listening port (default: 0) Použít UPnP k namapování naslouchacího portu (výchozí: 0) @@ -2698,32 +2731,32 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Soubor wallet.dat je poškozen, jeho záchrana se nezdařila - + Password for JSON-RPC connections Heslo pro JSON-RPC spojení - + Allow JSON-RPC connections from specified IP address Povolit JSON-RPC spojení ze specifikované IP adresy - + Send commands to node running on <ip> (default: 127.0.0.1) Posílat příkazy uzlu běžícím na <ip> (výchozí: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Spustit příkaz, když se změní nejlepší blok (%s se v příkazu nahradí hashem bloku) - + Upgrade wallet to latest format Převést peněženku na nejnovější formát - + Set key pool size to <n> (default: 100) Nastavit zásobník klíčů na velikost <n> (výchozí: 100) @@ -2733,12 +2766,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Přeskenovat řetězec bloků na chybějící transakce tvé pěněženky - + Use OpenSSL (https) for JSON-RPC connections Použít OpenSSL (https) pro JSON-RPC spojení - + Server certificate file (default: server.cert) Soubor se serverovým certifikátem (výchozí: server.cert) @@ -2748,22 +2781,22 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Soubor se serverovým soukromým klíčem (výchozí: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akceptovatelné šifry (výchozí: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Tato nápověda - + Unable to bind to %s on this computer (bind returned error %d, %s) Nedaří se mi připojit na %s na tomhle počítači (operace bind vrátila chybu %d, %s) - + Connect through socks proxy Připojit se přes socks proxy @@ -2773,12 +2806,12 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Povolit DNS dotazy pro -addnode (přidání uzlu), -seednode a -connect (připojení) - + Loading addresses... Načítám adresy... - + Error loading wallet.dat: Wallet corrupted Chyba při načítání wallet.dat: peněženka je poškozená @@ -2788,22 +2821,22 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chyba při načítání wallet.dat: peněženka vyžaduje novější verzi Bitcoinu - + Wallet needed to be rewritten: restart Bitcoin to complete Soubor s peněženkou potřeboval přepsat: restartuj Bitcoin, aby se operace dokončila - + Error loading wallet.dat Chyba při načítání wallet.dat - + Invalid -proxy address: '%s' Neplatná -proxy adresa: '%s' - + Unknown network specified in -onlynet: '%s' V -onlynet byla uvedena neznámá síť: '%s' @@ -2813,7 +2846,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. V -socks byla požadována neznámá verze proxy: %i - + Cannot resolve -bind address: '%s' Nemohu přeložit -bind adresu: '%s' @@ -2823,7 +2856,7 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nemohu přeložit -externalip adresu: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Neplatná částka pro -paytxfee=<částka>: '%s' @@ -2833,17 +2866,17 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Neplatná částka - + Insufficient funds Nedostatek prostředků - + Loading block index... Načítám index bloků... - + Add a node to connect to and attempt to keep the connection open Přidat uzel, ke kterému se připojit a snažit se spojení udržet @@ -2853,17 +2886,17 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nedaří se mi připojit na %s na tomhle počítači. Bitcoin už pravděpodobně jednou běží. - + Fee per KB to add to transactions you send Poplatek za kB, který se přidá ke každé odeslané transakci - + Loading wallet... Načítám peněženku... - + Cannot downgrade wallet Nemohu převést peněženku do staršího formátu @@ -2873,22 +2906,22 @@ například: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nemohu napsat výchozí adresu - + Rescanning... Přeskenovávám... - + Done loading Načítání dokončeno - + To use the %s option K použití volby %s - + Error Chyba diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index 862c23c2d..067e5ceb4 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 702a1598a..a90073e64 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -2132,6 +2132,14 @@ Adresse: %4 til + + WalletModel + + + Send Coins + Send bitcoins + + WalletView @@ -2183,12 +2191,12 @@ Adresse: %4 Bitcoin-version - + Usage: Anvendelse: - + Send command to -server or bitcoind Send kommando til -server eller bitcoind @@ -2198,17 +2206,17 @@ Adresse: %4 Liste over kommandoer - + Get help for a command Få hjælp til en kommando - + Options: Indstillinger: - + Specify configuration file (default: bitcoin.conf) Angiv konfigurationsfil (standard: bitcoin.conf) @@ -2223,7 +2231,7 @@ Adresse: %4 Angiv datakatalog - + Set database cache size in megabytes (default: 25) Angiv databasecachestørrelse i megabytes (standard: 25) @@ -2238,12 +2246,12 @@ Adresse: %4 Oprethold højest <n> forbindelser til andre i netværket (standard: 125) - + Connect to a node to retrieve peer addresses, and disconnect Forbind til en knude for at modtage adresse, og afbryd - + Specify your own public address Angiv din egen offentlige adresse @@ -2253,7 +2261,7 @@ Adresse: %4 Grænse for afbrydelse til dårlige forbindelser (standard: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Antal sekunder dårlige forbindelser skal vente før reetablering (standard: 86400) @@ -2273,17 +2281,17 @@ Adresse: %4 Accepter kommandolinje- og JSON-RPC-kommandoer - + Run in the background as a daemon and accept commands Kør i baggrunden som en service, og accepter kommandoer - + Use the test network Brug testnetværket - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepter forbindelser udefra (standard: 1 hvis hverken -proxy eller -connect) @@ -2437,11 +2445,6 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Error: Disk space is low! Fejl: Mangel på ledig diskplads! - - - Error: Transaction creation failed! - Fejl: Transaktionsoprettelse mislykkedes! - Error: Wallet locked, unable to create transaction! @@ -2528,7 +2531,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Grundighed af efterprøvning af blokke (0-4, standard: 3) - + Not enough file descriptors available. For få tilgængelige fildeskriptorer. @@ -2543,7 +2546,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Angiv antallet af tråde til at håndtere RPC-kald (standard: 4) - + Verifying blocks... Efterprøver blokke... @@ -2553,17 +2556,17 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Efterprøver tegnebog... - + Imports blocks from external blk000??.dat file Importerer blokke fra ekstern blk000??.dat fil - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Angiv nummeret af skriptefterprøvningstråde (op til 16, 0 = automatisk, <0 = efterlad det antal kerner tilgængelige, standard: 0) - + Information Information @@ -2572,6 +2575,16 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Invalid -tor address: '%s' Ugyldig -tor adresse: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ugyldigt beløb til -minrelaytxfee=<beløb>:'%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ugyldigt beløb til -mintxfee=<beløb>:'%s' + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Shrink debug.log file on client startup (default: 1 when no -debug) Formindsk debug.log filen ved klientopstart (standard: 1 hvis ikke -debug) + + + Signing transaction failed + Underskrift af transaktion mislykkedes + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Systemfejl: - + + Transaction amount too small + Transaktionsbeløb er for lavt + + + + Transaction amounts must be positive + Transaktionsbeløb skal være positive + + + + Transaction too large + Transaktionen er for stor + + + Use UPnP to map the listening port (default: 0) Forsøg at bruge UPnP til at konfigurere den lyttende port (standard: 0) @@ -2698,32 +2731,32 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com wallet.dat ødelagt, redning af data mislykkedes - + Password for JSON-RPC connections Adgangskode til JSON-RPC-forbindelser - + Allow JSON-RPC connections from specified IP address Tillad JSON-RPC-forbindelser fra bestemt IP-adresse - + Send commands to node running on <ip> (default: 127.0.0.1) Send kommandoer til knude, der kører på <ip> (standard: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Udfør kommando, når den bedste blok ændres (%s i kommandoen erstattes med blokhash) - + Upgrade wallet to latest format Opgrader tegnebog til seneste format - + Set key pool size to <n> (default: 100) Angiv nøglepoolstørrelse til <n> (standard: 100) @@ -2733,12 +2766,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Gennemsøg blokkæden for manglende tegnebogstransaktioner - + Use OpenSSL (https) for JSON-RPC connections Brug OpenSSL (https) for JSON-RPC-forbindelser - + Server certificate file (default: server.cert) Servercertifikat-fil (standard: server.cert) @@ -2748,22 +2781,22 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Serverens private nøgle (standard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Acceptable ciphers (standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Denne hjælpebesked - + Unable to bind to %s on this computer (bind returned error %d, %s) Kunne ikke tildele %s på denne computer (bind returnerede fejl %d, %s) - + Connect through socks proxy Tilslut via SOCKS-proxy @@ -2773,12 +2806,12 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Tillad DNS-opslag for -addnode, -seednode og -connect - + Loading addresses... Indlæser adresser... - + Error loading wallet.dat: Wallet corrupted Fejl ved indlæsning af wallet.dat: Tegnebog ødelagt @@ -2788,22 +2821,22 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Fejl ved indlæsning af wallet.dat: Tegnebog kræver en nyere version af Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Det var nødvendigt at genskrive tegnebogen: genstart Bitcoin for at gennemføre - + Error loading wallet.dat Fejl ved indlæsning af wallet.dat - + Invalid -proxy address: '%s' Ugyldig -proxy adresse: '%s' - + Unknown network specified in -onlynet: '%s' Ukendt netværk anført i -onlynet: '%s' @@ -2813,7 +2846,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Ukendt -socks proxy-version: %i - + Cannot resolve -bind address: '%s' Kan ikke finde -bind adressen: '%s' @@ -2823,7 +2856,7 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Kan ikke finde -externalip adressen: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ugyldigt beløb for -paytxfee=<amount>: '%s' @@ -2833,17 +2866,17 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Ugyldigt beløb - + Insufficient funds Manglende dækning - + Loading block index... Indlæser blokindeks... - + Add a node to connect to and attempt to keep the connection open Tilføj en knude til at forbinde til og forsøg at holde forbindelsen åben @@ -2853,17 +2886,17 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Kunne ikke tildele %s på denne computer. Bitcoin kører sikkert allerede. - + Fee per KB to add to transactions you send Gebyr pr. kB, som skal tilføjes til transaktioner, du sender - + Loading wallet... Indlæser tegnebog... - + Cannot downgrade wallet Kan ikke nedgradere tegnebog @@ -2873,22 +2906,22 @@ f.eks.: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Kan ikke skrive standardadresse - + Rescanning... Genindlæser... - + Done loading Indlæsning gennemført - + To use the %s option For at bruge %s mulighed - + Error Fejl diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index d5dbff0a9..5d857ee6f 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -2131,6 +2131,14 @@ Adresse: %4 bis + + WalletModel + + + Send Coins + Bitcoins überweisen + + WalletView @@ -2182,12 +2190,12 @@ Adresse: %4 Bitcoin-Version - + Usage: Benutzung: - + Send command to -server or bitcoind Befehl an -server oder bitcoind senden @@ -2197,17 +2205,17 @@ Adresse: %4 Befehle auflisten - + Get help for a command Hilfe zu einem Befehl erhalten - + Options: Optionen: - + Specify configuration file (default: bitcoin.conf) Konfigurationsdatei festlegen (Standard: bitcoin.conf) @@ -2222,7 +2230,7 @@ Adresse: %4 Datenverzeichnis festlegen - + Set database cache size in megabytes (default: 25) Größe des Datenbankcaches in MB festlegen (Standard: 25) @@ -2237,12 +2245,12 @@ Adresse: %4 Maximal <n> Verbindungen zu Gegenstellen aufrechterhalten (Standard: 125) - + Connect to a node to retrieve peer addresses, and disconnect Mit dem Knoten verbinden um Adressen von Gegenstellen abzufragen, danach trennen - + Specify your own public address Die eigene öffentliche Adresse angeben @@ -2252,7 +2260,7 @@ Adresse: %4 Schwellenwert, um Verbindungen zu sich nicht konform verhaltenden Gegenstellen zu beenden (Standard: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Anzahl Sekunden, während denen sich nicht konform verhaltenden Gegenstellen die Wiederverbindung verweigert wird (Standard: 86400) @@ -2272,17 +2280,17 @@ Adresse: %4 Kommandozeilenbefehle und JSON-RPC-Befehle annehmen - + Run in the background as a daemon and accept commands Als Hintergrunddienst starten und Befehle annehmen - + Use the test network Das Testnetz verwenden - + Accept connections from outside (default: 1 if no -proxy or -connect) Eingehende Verbindungen annehmen (Standard: 1, wenn nicht -proxy oder -connect) @@ -2436,11 +2444,6 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Error: Disk space is low! Fehler: Zu wenig freier Laufwerksspeicherplatz! - - - Error: Transaction creation failed! - Fehler: Transaktionserstellung fehlgeschlagen! - Error: Wallet locked, unable to create transaction! @@ -2527,7 +2530,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Wie gründlich soll die Blockprüfung sein (0-4, Standard: 3) - + Not enough file descriptors available. Nicht genügend File-Deskriptoren verfügbar. @@ -2542,7 +2545,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Maximale Anzahl an Threads zur Verarbeitung von RPC-Anfragen festlegen (Standard: 4) - + Verifying blocks... Verifiziere Blöcke... @@ -2552,17 +2555,17 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Verifiziere Brieftasche... - + Imports blocks from external blk000??.dat file Blöcke aus externer Datei blk000??.dat importieren - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (bis zu 16, 0 = automatisch, <0 = soviele Kerne frei lassen, Standard: 0) - + Information Hinweis @@ -2571,6 +2574,16 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Invalid -tor address: '%s' Ungültige Adresse in -tor: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ungültiger Betrag für -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ungültiger Betrag für -mintxfee=<amount>: '%s' + Maintain a full transaction index (default: 0) @@ -2646,6 +2659,11 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Shrink debug.log file on client startup (default: 1 when no -debug) Verkleinere Datei debug.log beim Start des Clients (Standard: 1, wenn kein -debug) + + + Signing transaction failed + Signierung der Transaktion fehlgeschlagen + Specify connection timeout in milliseconds (default: 5000) @@ -2657,7 +2675,22 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Systemfehler: - + + Transaction amount too small + Transaktionsbetrag zu gering + + + + Transaction amounts must be positive + Transaktionsbeträge müssen positiv sein + + + + Transaction too large + Transaktion zu groß + + + Use UPnP to map the listening port (default: 0) UPnP verwenden, um die Portweiterleitung einzurichten (Standard: 0) @@ -2697,32 +2730,32 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f wallet.dat beschädigt, Rettung fehlgeschlagen - + Password for JSON-RPC connections Passwort für JSON-RPC-Verbindungen - + Allow JSON-RPC connections from specified IP address JSON-RPC-Verbindungen von der angegebenen IP-Adresse erlauben - + Send commands to node running on <ip> (default: 127.0.0.1) Sende Befehle an Knoten <ip> (Standard: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Kommando ausführen wenn der beste Block wechselt (%s im Kommando wird durch den Hash des Blocks ersetzt) - + Upgrade wallet to latest format Brieftasche auf das neueste Format aktualisieren - + Set key pool size to <n> (default: 100) Größe des Schlüsselpools festlegen auf <n> (Standard: 100) @@ -2732,12 +2765,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Blockkette erneut nach fehlenden Transaktionen der Brieftasche durchsuchen - + Use OpenSSL (https) for JSON-RPC connections OpenSSL (https) für JSON-RPC-Verbindungen verwenden - + Server certificate file (default: server.cert) Serverzertifikat (Standard: server.cert) @@ -2747,22 +2780,22 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Privater Serverschlüssel (Standard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akzeptierte Chiffren (Standard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Dieser Hilfetext - + Unable to bind to %s on this computer (bind returned error %d, %s) Kann auf diesem Computer nicht an %s binden (von bind zurückgegebener Fehler %d, %s) - + Connect through socks proxy Verbindung über SOCKS-Proxy herstellen @@ -2772,12 +2805,12 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Erlaube DNS-Namensauflösung für -addnode, -seednode und -connect - + Loading addresses... Lade Adressen... - + Error loading wallet.dat: Wallet corrupted Fehler beim Laden von wallet.dat: Brieftasche beschädigt @@ -2787,22 +2820,22 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Fehler beim Laden von wallet.dat: Brieftasche benötigt neuere Version von Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Brieftasche musste neu geschrieben werden: Starten Sie Bitcoin zur Fertigstellung neu - + Error loading wallet.dat Fehler beim Laden von wallet.dat (Brieftasche) - + Invalid -proxy address: '%s' Ungültige Adresse in -proxy: '%s' - + Unknown network specified in -onlynet: '%s' Unbekannter Netztyp in -onlynet angegeben: '%s' @@ -2812,7 +2845,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Unbekannte Proxyversion in -socks angefordert: %i - + Cannot resolve -bind address: '%s' Kann Adresse in -bind nicht auflösen: '%s' @@ -2822,9 +2855,9 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Kann Adresse in -externalip nicht auflösen: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' - Ungültiger Betrag für -paytxfee=<Betrag>: '%s' + Ungültiger Betrag für -paytxfee=<amount>: '%s' @@ -2832,17 +2865,17 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Ungültiger Betrag - + Insufficient funds Unzureichender Kontostand - + Loading block index... Lade Blockindex... - + Add a node to connect to and attempt to keep the connection open Mit dem Knoten verbinden und versuchen die Verbindung aufrecht zu halten @@ -2852,17 +2885,17 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Kann auf diesem Computer nicht an %s binden. Evtl. wurde Bitcoin bereits gestartet. - + Fee per KB to add to transactions you send Gebühr pro KB, die gesendeten Transaktionen hinzugefügt wird - + Loading wallet... Lade Brieftasche... - + Cannot downgrade wallet Brieftasche kann nicht auf eine ältere Version herabgestuft werden @@ -2872,22 +2905,22 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f Standardadresse kann nicht geschrieben werden - + Rescanning... Durchsuche erneut... - + Done loading Laden abgeschlossen - + To use the %s option Zur Nutzung der %s Option - + Error Fehler diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index f7073c465..9d197f58e 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -2127,6 +2127,14 @@ Address: %4 έως + + WalletModel + + + Send Coins + Αποστολή νομισμάτων + + WalletView @@ -2178,12 +2186,12 @@ Address: %4 Έκδοση Bitcoin - + Usage: Χρήση: - + Send command to -server or bitcoind Αποστολή εντολής στον εξυπηρετητή ή στο bitcoind @@ -2193,17 +2201,17 @@ Address: %4 Λίστα εντολών - + Get help for a command Επεξήγηση εντολής - + Options: Επιλογές: - + Specify configuration file (default: bitcoin.conf) Ορίστε αρχείο ρυθμίσεων (προεπιλογή: bitcoin.conf) @@ -2218,7 +2226,7 @@ Address: %4 Ορισμός φακέλου δεδομένων - + Set database cache size in megabytes (default: 25) Όρισε το μέγεθος της βάσης προσωρινής αποθήκευσης σε megabytes(προεπιλογή:25) @@ -2233,12 +2241,12 @@ Address: %4 Μέγιστες αριθμός συνδέσεων με τους peers <n> (προεπιλογή: 125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address Διευκρινίστε τη δικιά σας δημόσια διεύθυνση. @@ -2248,7 +2256,7 @@ Address: %4 Όριο αποσύνδεσης προβληματικών peers (προεπιλογή: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Δευτερόλεπτα πριν επιτραπεί ξανά η σύνδεση των προβληματικών peers (προεπιλογή: 86400) @@ -2268,17 +2276,17 @@ Address: %4 Αποδοχή εντολών κονσόλας και JSON-RPC - + Run in the background as a daemon and accept commands Εκτέλεση στο παρασκήνιο κι αποδοχή εντολών - + Use the test network Χρήση του δοκιμαστικού δικτύου - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2422,11 +2430,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2513,7 +2516,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2528,7 +2531,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2538,17 +2541,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2557,6 +2560,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2632,6 +2645,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2643,7 +2661,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Λάθος Συστήματος: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2683,32 +2716,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Κωδικός για τις συνδέσεις JSON-RPC - + Allow JSON-RPC connections from specified IP address Αποδοχή συνδέσεων JSON-RPC από συγκεκριμένη διεύθυνση IP - + Send commands to node running on <ip> (default: 127.0.0.1) Αποστολή εντολών στον κόμβο <ip> (προεπιλογή: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) - + Upgrade wallet to latest format Αναβάθμισε το πορτοφόλι στην τελευταία έκδοση - + Set key pool size to <n> (default: 100) Όριο πλήθους κλειδιών pool <n> (προεπιλογή: 100) @@ -2718,12 +2751,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Επανέλεγχος της αλυσίδας μπλοκ για απούσες συναλλαγές - + Use OpenSSL (https) for JSON-RPC connections Χρήση του OpenSSL (https) για συνδέσεις JSON-RPC - + Server certificate file (default: server.cert) Αρχείο πιστοποιητικού του διακομιστή (προεπιλογή: server.cert) @@ -2733,22 +2766,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Προσωπικό κλειδί του διακομιστή (προεπιλογή: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Αποδεκτά κρυπτογραφήματα (προεπιλογή: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Αυτό το κείμενο βοήθειας - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy Σύνδεση μέσω διαμεσολαβητή socks @@ -2758,12 +2791,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... Φόρτωση διευθύνσεων... - + Error loading wallet.dat: Wallet corrupted Σφάλμα φόρτωσης wallet.dat: Κατεστραμμένο Πορτοφόλι @@ -2773,22 +2806,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Σφάλμα φόρτωσης wallet.dat: Το Πορτοφόλι απαιτεί μια νεότερη έκδοση του Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Απαιτείται η επανεγγραφή του Πορτοφολιού, η οποία θα ολοκληρωθεί στην επανεκκίνηση του Bitcoin - + Error loading wallet.dat Σφάλμα φόρτωσης αρχείου wallet.dat - + Invalid -proxy address: '%s' Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2798,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2808,7 +2841,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2818,17 +2851,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Λάθος ποσότητα - + Insufficient funds Ανεπαρκές κεφάλαιο - + Loading block index... Φόρτωση ευρετηρίου μπλοκ... - + Add a node to connect to and attempt to keep the connection open Προσέθεσε ένα κόμβο για σύνδεση και προσπάθησε να κρατήσεις την σύνδεση ανοιχτή @@ -2838,17 +2871,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send Αμοιβή ανά KB που θα προστίθεται στις συναλλαγές που στέλνεις - + Loading wallet... Φόρτωση πορτοφολιού... - + Cannot downgrade wallet Δεν μπορώ να υποβαθμίσω το πορτοφόλι @@ -2858,22 +2891,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Δεν μπορώ να γράψω την προεπιλεγμένη διεύθυνση - + Rescanning... Ανίχνευση... - + Done loading Η φόρτωση ολοκληρώθηκε - + To use the %s option Χρήση της %s επιλογής - + Error Σφάλμα diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index 1e2281f75..04a65147f 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 Bitcoin-a versio - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 Listigu instrukciojn - + Get help for a command - + Options: Opcioj: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... Ŝarĝante adresojn... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... Ŝarĝante blok-indekson... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... Ŝarĝante monujon... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading Ŝarĝado finitas - + To use the %s option Por uzi la opcion %s - + Error Eraro diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index ef38c0f64..26e3993dd 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -2135,6 +2135,14 @@ Dirección: %4 para + + WalletModel + + + Send Coins + Enviar monedas + + WalletView @@ -2186,12 +2194,12 @@ Dirección: %4 Versión de Bitcoin - + Usage: Uso: - + Send command to -server or bitcoind Envíar comando a -server o bitcoind @@ -2202,19 +2210,19 @@ Dirección: %4 - + Get help for a command Recibir ayuda para un comando - + Options: Opciones: - + Specify configuration file (default: bitcoin.conf) Especificar archivo de configuración (predeterminado: bitcoin.conf) @@ -2231,7 +2239,7 @@ Dirección: %4 Especificar directorio para los datos - + Set database cache size in megabytes (default: 25) Establecer el tamaño de caché de la base de datos en megabytes (predeterminado: 25) @@ -2246,12 +2254,12 @@ Dirección: %4 Mantener como máximo <n> conexiones a pares (predeterminado: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conectar a un nodo para obtener direcciones de pares y desconectar - + Specify your own public address Especifique su propia dirección pública @@ -2261,7 +2269,7 @@ Dirección: %4 Umbral para la desconexión de pares con mal comportamiento (predeterminado: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Número de segundos en que se evita la reconexión de pares con mal comportamiento (predeterminado: 86400) @@ -2282,19 +2290,19 @@ Dirección: %4 - + Run in the background as a daemon and accept commands Correr como demonio y aceptar comandos - + Use the test network Usar la red de pruebas - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect) @@ -2448,11 +2456,6 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Error: ¡Espacio en disco bajo! - - - Error: Transaction creation failed! - Error: ¡Ha fallado la creación de la transacción! - Error: Wallet locked, unable to create transaction! @@ -2539,7 +2542,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Como es de exhaustiva la verificación de bloques (0-4, por defecto 3) - + Not enough file descriptors available. No hay suficientes descriptores de archivo disponibles. @@ -2554,7 +2557,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Establecer el número de hilos para atender las llamadas RPC (predeterminado: 4) - + Verifying blocks... Verificando bloques... @@ -2564,17 +2567,17 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verificando monedero... - + Imports blocks from external blk000??.dat file Importa los bloques desde un archivo blk000??.dat externo - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Configura el número de hilos para el script de verificación (hasta 16, 0 = auto, <0 = leave that many cores free, por fecto: 0) - + Information Información @@ -2583,6 +2586,16 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Dirección -tor inválida: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Inválido por el monto -minrelaytxfee=<amount>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Inválido por el monto -mintxfee=<amount>: '%s' + Maintain a full transaction index (default: 0) @@ -2658,6 +2671,11 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Reducir el archivo debug.log al iniciar el cliente (predeterminado: 1 sin -debug) + + + Signing transaction failed + Transacción falló + Specify connection timeout in milliseconds (default: 5000) @@ -2669,7 +2687,22 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error de sistema: - + + Transaction amount too small + Monto de la transacción muy pequeño + + + + Transaction amounts must be positive + Montos de transacciones deben ser positivos + + + + Transaction too large + Transacción demasiado grande + + + Use UPnP to map the listening port (default: 0) Usar UPnP para asignar el puerto de escucha (predeterminado: 0) @@ -2710,35 +2743,35 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat corrupto. Ha fallado la recuperación. - + Password for JSON-RPC connections Contraseña para las conexiones JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitir conexiones JSON-RPC desde la dirección IP especificada - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comando al nodo situado en <ip> (predeterminado: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque) - + Upgrade wallet to latest format Actualizar el monedero al último formato - + Set key pool size to <n> (default: 100) Ajustar el número de claves en reserva <n> (predeterminado: 100) @@ -2749,13 +2782,13 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Volver a examinar la cadena de bloques en busca de transacciones del monedero perdidas - + Use OpenSSL (https) for JSON-RPC connections Usar OpenSSL (https) para las conexiones JSON-RPC - + Server certificate file (default: server.cert) Certificado del servidor (predeterminado: server.cert) @@ -2767,24 +2800,24 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrados aceptados (predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Este mensaje de ayuda - + Unable to bind to %s on this computer (bind returned error %d, %s) No es posible conectar con %s en este sistema (bind ha dado el error %d, %s) - + Connect through socks proxy Conectar mediante proxy socks @@ -2794,12 +2827,12 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Permitir búsquedas DNS para -addnode, -seednode y -connect - + Loading addresses... Cargando direcciones... - + Error loading wallet.dat: Wallet corrupted Error al cargar wallet.dat: el monedero está dañado @@ -2809,22 +2842,22 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error al cargar wallet.dat: El monedero requiere una versión más reciente de Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete El monedero ha necesitado ser reescrito. Reinicie Bitcoin para completar el proceso - + Error loading wallet.dat Error al cargar wallet.dat - + Invalid -proxy address: '%s' Dirección -proxy inválida: '%s' - + Unknown network specified in -onlynet: '%s' La red especificada en -onlynet '%s' es desconocida @@ -2834,7 +2867,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Solicitada versión de proxy -socks desconocida: %i - + Cannot resolve -bind address: '%s' No se puede resolver la dirección de -bind: '%s' @@ -2844,7 +2877,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No se puede resolver la dirección de -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Cantidad inválida para -paytxfee=<amount>: '%s' @@ -2854,17 +2887,17 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cuantía no válida - + Insufficient funds Fondos insuficientes - + Loading block index... Cargando el índice de bloques... - + Add a node to connect to and attempt to keep the connection open Añadir un nodo al que conectarse y tratar de mantener la conexión abierta @@ -2874,17 +2907,17 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es posible conectar con %s en este sistema. Probablemente Bitcoin ya está ejecutándose. - + Fee per KB to add to transactions you send Tarifa por KB que añadir a las transacciones que envíe - + Loading wallet... Cargando monedero... - + Cannot downgrade wallet No se puede rebajar el monedero @@ -2894,22 +2927,22 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No se puede escribir la dirección predeterminada - + Rescanning... Rescaneando... - + Done loading Generado pero no aceptado - + To use the %s option Para utilizar la opción %s - + Error Error diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index 78d59bd16..29ac9ea2e 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -2135,6 +2135,14 @@ Dirección: %4 para + + WalletModel + + + Send Coins + Enviar monedas + + WalletView @@ -2186,12 +2194,12 @@ Dirección: %4 Versión Bitcoin - + Usage: Uso: - + Send command to -server or bitcoind Envia comando a bitcoin lanzado con -server u bitcoind @@ -2203,19 +2211,19 @@ Dirección: %4 - + Get help for a command Recibir ayuda para un comando - + Options: Opciones: - + Specify configuration file (default: bitcoin.conf) Especifica archivo de configuración (predeterminado: bitcoin.conf) @@ -2233,7 +2241,7 @@ Dirección: %4 - + Set database cache size in megabytes (default: 25) @@ -2248,12 +2256,12 @@ Dirección: %4 Mantener al menos <n> conecciones por cliente (por defecto: 125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2263,7 +2271,7 @@ Dirección: %4 Umbral de desconección de clientes con mal comportamiento (por defecto: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2284,19 +2292,19 @@ Dirección: %4 - + Run in the background as a daemon and accept commands Correr como demonio y acepta comandos - + Use the test network Usa la red de pruebas - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2441,11 +2449,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2532,7 +2535,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2547,7 +2550,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2557,17 +2560,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2576,6 +2579,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Dirección -tor invalida: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2651,6 +2664,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2662,7 +2680,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Intenta usar UPnP para mapear el puerto de escucha (default: 0) @@ -2703,35 +2736,35 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Contraseña para las conexiones JSON-RPC - + Allow JSON-RPC connections from specified IP address Permite conexiones JSON-RPC desde la dirección IP especificada - + Send commands to node running on <ip> (default: 127.0.0.1) Envia comando al nodo situado en <ip> (predeterminado: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format Actualizar billetera al formato actual - + Set key pool size to <n> (default: 100) Ajusta el numero de claves en reserva <n> (predeterminado: 100) @@ -2743,13 +2776,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections Usa OpenSSL (https) para las conexiones JSON-RPC - + Server certificate file (default: server.cert) Certificado del servidor (Predeterminado: server.cert) @@ -2761,24 +2794,24 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrados aceptados (Predeterminado: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Este mensaje de ayuda - + Unable to bind to %s on this computer (bind returned error %d, %s) No es posible escuchar en el %s en este ordenador (bind returned error %d, %s) - + Connect through socks proxy Conecta mediante proxy socks @@ -2789,12 +2822,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... Cargando direcciónes... - + Error loading wallet.dat: Wallet corrupted Error cargando wallet.dat: Billetera corrupta @@ -2804,22 +2837,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error cargando wallet.dat: Billetera necesita una vercion reciente de Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete La billetera necesita ser reescrita: reinicie Bitcoin para completar - + Error loading wallet.dat Error cargando wallet.dat - + Invalid -proxy address: '%s' Dirección -proxy invalida: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2829,7 +2862,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2839,7 +2872,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Cantidad inválida para -paytxfee=<amount>: '%s' @@ -2849,17 +2882,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cantidad inválida - + Insufficient funds Fondos insuficientes - + Loading block index... Cargando el index de bloques... - + Add a node to connect to and attempt to keep the connection open Agrega un nodo para conectarse and attempt to keep the connection open @@ -2869,17 +2902,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. No es posible escuchar en el %s en este ordenador. Probablemente Bitcoin ya se está ejecutando. - + Fee per KB to add to transactions you send Comisión por kB para adicionarla a las transacciones enviadas - + Loading wallet... Cargando cartera... - + Cannot downgrade wallet @@ -2889,22 +2922,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... Rescaneando... - + Done loading Carga completa - + To use the %s option - + Error Error diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index c5ae7b0b2..79e6ae8ec 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -2131,6 +2131,14 @@ Aadress: %4⏎ saaja + + WalletModel + + + Send Coins + + + WalletView @@ -2182,12 +2190,12 @@ Aadress: %4⏎ Bitcoini versioon - + Usage: Kasutus: - + Send command to -server or bitcoind Saada käsklus -serverile või bitcoindile @@ -2197,17 +2205,17 @@ Aadress: %4⏎ Käskluste loetelu - + Get help for a command Käskluste abiinfo - + Options: Valikud: - + Specify configuration file (default: bitcoin.conf) Täpsusta sätete fail (vaikimisi: bitcoin.conf) @@ -2222,7 +2230,7 @@ Aadress: %4⏎ Täpsusta andmekataloog - + Set database cache size in megabytes (default: 25) Sea andmebaasi vahemälu suurus MB (vaikeväärtus: 25) @@ -2237,12 +2245,12 @@ Aadress: %4⏎ Säilita vähemalt <n> ühendust peeridega (vaikeväärtus: 125) - + Connect to a node to retrieve peer addresses, and disconnect Peeri aadressi saamiseks ühendu korraks node'iga - + Specify your own public address Täpsusta enda avalik aadress @@ -2252,7 +2260,7 @@ Aadress: %4⏎ Ulakate peeride valulävi (vaikeväärtus: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Mitme sekundi pärast ulakad peerid tagasi võivad tulla (vaikeväärtus: 86400) @@ -2272,17 +2280,17 @@ Aadress: %4⏎ Luba käsurea ning JSON-RPC käsklusi - + Run in the background as a daemon and accept commands Tööta taustal ning aktsepteeri käsklusi - + Use the test network Testvõrgu kasutamine - + Accept connections from outside (default: 1 if no -proxy or -connect) Luba välisühendusi (vaikeväärtus: 1 kui puudub -proxy või -connect) @@ -2436,11 +2444,6 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Error: Disk space is low! Tõrge: liiga vähe kettaruumi! - - - Error: Transaction creation failed! - Tõrge: Tehingu loomine ebaõnnestus! - Error: Wallet locked, unable to create transaction! @@ -2527,7 +2530,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Blokkide kontrollimise põhjalikkus (0-4, vaikeväärtus: 3) - + Not enough file descriptors available. @@ -2542,7 +2545,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Määra RPC kõnede haldurite arv (vaikeväärtus: 4) - + Verifying blocks... Kontrollin blokke... @@ -2552,17 +2555,17 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Kontrollin rahakotti... - + Imports blocks from external blk000??.dat file Impordi blokid välisest blk000??.dat failist - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Informatsioon @@ -2571,6 +2574,16 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Invalid -tor address: '%s' Vigane -tor aadress: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2646,6 +2659,11 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Shrink debug.log file on client startup (default: 1 when no -debug) Kahanda programmi käivitamisel debug.log faili (vaikeväärtus: 1, kui ei ole -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2657,7 +2675,22 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Süsteemi tõrge: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Kasuta kuulatava pordi määramiseks UPnP ühendust (vaikeväärtus: 0) @@ -2697,32 +2730,32 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com wallet.dat fail on katki, päästmine ebaõnnestus - + Password for JSON-RPC connections JSON-RPC ühenduste salasõna - + Allow JSON-RPC connections from specified IP address JSON-RPC ühenduste lubamine kindla IP pealt - + Send commands to node running on <ip> (default: 127.0.0.1) Saada käsklusi node'ile IP'ga <ip> (vaikeväärtus: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Käivita käsklus, kui parim plokk muutub (käskluse %s asendatakse ploki hash'iga) - + Upgrade wallet to latest format Uuenda rahakott uusimasse vormingusse - + Set key pool size to <n> (default: 100) Sea võtmete hulgaks <n> (vaikeväärtus: 100) @@ -2732,12 +2765,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Otsi ploki jadast rahakoti kadunud tehinguid - + Use OpenSSL (https) for JSON-RPC connections Kasuta JSON-RPC ühenduste jaoks OpenSSL'i (https) - + Server certificate file (default: server.cert) Serveri sertifikaadifail (vaikeväärtus: server.cert) @@ -2747,22 +2780,22 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Serveri privaatvõti (vaikeväärtus: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Lubatud šiffrid (vaikeväärtus: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Käesolev abitekst - + Unable to bind to %s on this computer (bind returned error %d, %s) Selle arvutiga ei ole võimalik siduda %s külge (katse nurjus %d, %s tõttu) - + Connect through socks proxy Ühendu läbi turva proxi @@ -2772,12 +2805,12 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com -addnode, -seednode ja -connect tohivad kasutada DNS lookup'i - + Loading addresses... Aadresside laadimine... - + Error loading wallet.dat: Wallet corrupted Viga wallet.dat käivitamisel. Vigane rahakkott @@ -2787,22 +2820,22 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Viga wallet.dat käivitamisel: Rahakott nõuab Bitcoini uusimat versiooni - + Wallet needed to be rewritten: restart Bitcoin to complete Rahakott tuli ümberkirjutada: toimingu lõpetamiseks taaskäivita Bitcoin - + Error loading wallet.dat Viga wallet.dat käivitamisel - + Invalid -proxy address: '%s' Vigane -proxi aadress: '%s' - + Unknown network specified in -onlynet: '%s' Kirjeldatud tundmatu võrgustik -onlynet'is: '%s' @@ -2812,7 +2845,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Küsitud tundmatu -socks proxi versioon: %i - + Cannot resolve -bind address: '%s' Tundmatu -bind aadress: '%s' @@ -2822,7 +2855,7 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Tundmatu -externalip aadress: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<amount> jaoks vigane kogus: '%s' @@ -2832,17 +2865,17 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Kehtetu summa - + Insufficient funds Liiga suur summa - + Loading block index... Klotside indeksi laadimine... - + Add a node to connect to and attempt to keep the connection open Lisa node ning hoia ühendus avatud @@ -2852,17 +2885,17 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com %s'ga ei ole võimalik sellest arvutist siduda. Bitcoin juba töötab. - + Fee per KB to add to transactions you send Minu saadetavate tehingute lisatasu KB kohta - + Loading wallet... Rahakoti laadimine... - + Cannot downgrade wallet Rahakoti vanandamine ebaõnnestus @@ -2872,22 +2905,22 @@ nt: alertnotify=echo %%s | email -s "Bitcoin Alert" admin@foo.com Tõrge vaikimisi aadressi kirjutamisel - + Rescanning... Üleskaneerimine... - + Done loading Laetud - + To use the %s option %s valiku kasutamine - + Error Tõrge diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index bfc228b87..4928eedb3 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 Botcoin bertsioa - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 Komandoen lista - + Get help for a command Laguntza komando batean - + Options: Aukerak - + Specify configuration file (default: bitcoin.conf) Ezarpen fitxategia aukeratu (berezkoa: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Laguntza mezu hau - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... Birbilatzen... - + Done loading Zamaketa amaitua - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 210f607c1..ad1a69b68 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -2130,6 +2130,14 @@ Address: %4 به + + WalletModel + + + Send Coins + ارسال سکه ها + + WalletView @@ -2181,12 +2189,12 @@ Address: %4 سخه بیتکویین - + Usage: ستفاده : - + Send command to -server or bitcoind ارسال فرمان به سرور یا باتکویین @@ -2196,17 +2204,17 @@ Address: %4 لیست فومان ها - + Get help for a command کمک برای فرمان - + Options: تنظیمات - + Specify configuration file (default: bitcoin.conf) (: bitcoin.confپیش فرض: )فایل تنظیمی خاص @@ -2221,7 +2229,7 @@ Address: %4 دایرکتور اطلاعاتی خاص - + Set database cache size in megabytes (default: 25) سایز کَش بانک داده را بر حسب مگابایت تنظیم کنید (پیش فرض:25) @@ -2236,12 +2244,12 @@ Address: %4 حداکثر <n> اتصال با همکاران برقرار داشته باشید (پیش‌فرض: 125) - + Connect to a node to retrieve peer addresses, and disconnect اتصال به گره برای دریافت آدرسهای قرینه و قطع اتصال - + Specify your own public address آدرس عمومی خود را ذکر کنید @@ -2251,7 +2259,7 @@ Address: %4 آستانه برای قطع ارتباط با همکاران بدرفتار (پیش‌فرض: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) مدت زمان به ثانیه برای جلوگیری از همکاران بدرفتار برای اتصال دوباره (پیش‌فرض: 86400) @@ -2271,17 +2279,17 @@ Address: %4 JSON-RPC قابل فرمانها و - + Run in the background as a daemon and accept commands اجرای در پس زمینه به عنوان شبح و قبول فرمان ها - + Use the test network استفاده شبکه آزمایش - + Accept connections from outside (default: 1 if no -proxy or -connect) پذیرش اتصالات از بیرون (پیش فرض:1 بدون پراکسی یا اتصال) @@ -2425,11 +2433,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2516,7 +2519,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2531,7 +2534,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2541,17 +2544,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2560,6 +2563,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' آدرس نرم افزار تور غلط است %s + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2635,6 +2648,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) فایل debug.log را در startup مشتری کوچک کن (پیش فرض:1 اگر اشکال زدایی روی نداد) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2646,7 +2664,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) از UPnP برای شناسایی درگاه شنیداری استفاده کنید (پیش فرض:0) @@ -2686,32 +2719,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections JSON-RPC عبارت عبور برای ارتباطات - + Allow JSON-RPC connections from specified IP address از آدرس آی پی خاص JSON-RPC قبول ارتباطات - + Send commands to node running on <ip> (default: 127.0.0.1) (127.0.0.1پیش فرض: ) &lt;ip&gt; دادن فرمانها برای استفاده گره ها روی - + Execute command when the best block changes (%s in cmd is replaced by block hash) زمانی که بهترین بلاک تغییر کرد، دستور را اجرا کن (%s در cmd با block hash جایگزین شده است) - + Upgrade wallet to latest format wallet را به جدیدترین فرمت روزآمد کنید - + Set key pool size to <n> (default: 100) (100پیش فرض:)&lt;n&gt; گذاشتن اندازه کلید روی @@ -2721,12 +2754,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. اسکان مجدد زنجیر بلوکها برای گم والت معامله - + Use OpenSSL (https) for JSON-RPC connections JSON-RPCبرای ارتباطات استفاده کنید OpenSSL (https) - + Server certificate file (default: server.cert) (server.certپیش فرض: )گواهی نامه سرور @@ -2736,22 +2769,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. (server.pemپیش فرض: ) کلید خصوصی سرور - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) رمز های قابل قبول( TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message پیام کمکی - + Unable to bind to %s on this computer (bind returned error %d, %s) امکان اتصال به %s از این رایانه وجود ندارد ( bind returned error %d, %s) - + Connect through socks proxy اتصال از طریق پراکسی ساکس @@ -2761,12 +2794,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. به DNS اجازه بده تا برای addnode ، seednode و اتصال جستجو کند - + Loading addresses... بار گیری آدرس ها - + Error loading wallet.dat: Wallet corrupted خطا در بارگیری wallet.dat: کیف پول خراب شده است @@ -2776,22 +2809,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. خطا در بارگیری wallet.dat: کیف پول به ویرایش جدیدتری از Biticon نیاز دارد - + Wallet needed to be rewritten: restart Bitcoin to complete سلام - + Error loading wallet.dat خطا در بارگیری wallet.dat - + Invalid -proxy address: '%s' آدرس پراکسی اشتباه %s - + Unknown network specified in -onlynet: '%s' شبکه مشخص شده غیرقابل شناسایی در onlynet: '%s' @@ -2801,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. نسخه پراکسی ساکس غیرقابل شناسایی درخواست شده است: %i - + Cannot resolve -bind address: '%s' آدرس قابل اتصال- شناسایی نیست %s @@ -2811,7 +2844,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. آدرس خارجی قابل اتصال- شناسایی نیست %s - + Invalid amount for -paytxfee=<amount>: '%s' میزان وجه اشتباه برای paytxfee=<میزان وجه>: %s @@ -2821,17 +2854,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. میزان وجه اشتباه - + Insufficient funds بود جه نا کافی - + Loading block index... بار گیری شاخص بلوک - + Add a node to connect to and attempt to keep the connection open به اتصال یک گره اضافه کنید و اتصال را باز نگاه دارید @@ -2841,17 +2874,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. اتصال به %s از این رایانه امکان پذیر نیست. Bitcoin احتمالا در حال اجراست. - + Fee per KB to add to transactions you send پر داجت برای هر کیلو بیت برای اضافه به معامله ارسال - + Loading wallet... بار گیری والت - + Cannot downgrade wallet امکان تنزل نسخه در wallet وجود ندارد @@ -2861,22 +2894,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. آدرس پیش فرض قابل ذخیره نیست - + Rescanning... اسکان مجدد - + Done loading بار گیری انجام شده است - + To use the %s option برای استفاده از %s از انتخابات - + Error خطا diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index f1ec3587c..db8dd56e9 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -2126,6 +2126,14 @@ Address: %4 به + + WalletModel + + + Send Coins + سکه های ارسالی + + WalletView @@ -2177,12 +2185,12 @@ Address: %4 نسخه bitcoin - + Usage: میزان استفاده: - + Send command to -server or bitcoind ارسال دستور به سرور یا bitcoined @@ -2192,17 +2200,17 @@ Address: %4 فهرست دستورها - + Get help for a command درخواست کمک برای یک دستور - + Options: انتخابها: - + Specify configuration file (default: bitcoin.conf) فایل پیکربندیِ را مشخص کنید (پیش فرض: bitcoin.conf) @@ -2217,7 +2225,7 @@ Address: %4 دایرکتوری داده را مشخص کن - + Set database cache size in megabytes (default: 25) حافظه بانک داده را به مگابایت تنظیم کنید (پیش فرض: 25) @@ -2232,12 +2240,12 @@ Address: %4 نگهداری <N> ارتباطات برای قرینه سازی (پیش فرض:125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2247,7 +2255,7 @@ Address: %4 آستانه قطع برای قرینه سازی اشتباه (پیش فرض:100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) تعداد ثانیه ها برای اتصال دوباره قرینه های اشتباه (پیش فرض:86400) @@ -2267,17 +2275,17 @@ Address: %4 command line و JSON-RPC commands را قبول کنید - + Run in the background as a daemon and accept commands به عنوان daemon بک گراند را اجرا کنید و دستورات را قبول نمایید - + Use the test network از تستِ شبکه استفاده نمایید - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2421,11 +2429,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2512,7 +2515,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2527,7 +2530,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2537,17 +2540,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2556,6 +2559,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2631,6 +2644,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2642,7 +2660,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2682,32 +2715,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections رمز برای ارتباطاتِ JSON-RPC - + Allow JSON-RPC connections from specified IP address ارتباطاتِ JSON-RPC را از آدرس آی.پی. مشخصی برقرار کنید. - + Send commands to node running on <ip> (default: 127.0.0.1) دستورات را به گره اجرا شده در<ip> ارسال کنید (پیش فرض:127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) دستور را وقتی بهترین بلاک تغییر کرد اجرا کن (%s در دستور توسط block hash جایگزین شده است) - + Upgrade wallet to latest format wallet را به جدیدترین نسخه روزآمد کنید - + Set key pool size to <n> (default: 100) حجم key pool را به اندازه <n> تنظیم کنید (پیش فرض:100) @@ -2717,12 +2750,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. زنجیره بلاک را برای تراکنش جا افتاده در WALLET دوباره اسکن کنید - + Use OpenSSL (https) for JSON-RPC connections برای ارتباطاتِ JSON-RPC از OpenSSL (https) استفاده کنید - + Server certificate file (default: server.cert) فایل certificate سرور (پیش فرض server.cert) @@ -2732,22 +2765,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. رمز اختصاصی سرور (پیش فرض: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) ciphers قابل قبول (پیش فرض: default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message این پیام راهنما - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2757,12 +2790,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... لود شدن آدرسها.. - + Error loading wallet.dat: Wallet corrupted خطا در هنگام لود شدن wallet.dat: Wallet corrupted @@ -2772,22 +2805,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. خطا در هنگام لود شدن wallet.dat. به نسخه جدید Bitocin برای wallet نیاز است. - + Wallet needed to be rewritten: restart Bitcoin to complete wallet نیاز به بازنویسی دارد. Bitcoin را برای تکمیل عملیات دوباره اجرا کنید. - + Error loading wallet.dat خطا در هنگام لود شدن wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2797,7 +2830,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2807,7 +2840,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' میزان اشتباه است for -paytxfee=<amount>: '%s' @@ -2817,17 +2850,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. میزان اشتباه است - + Insufficient funds وجوه ناکافی - + Loading block index... لود شدن نمایه بلاکها.. - + Add a node to connect to and attempt to keep the connection open یک گره برای اتصال اضافه کنید و تلاش کنید تا اتصال را باز نگاه دارید @@ -2837,17 +2870,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send هزینه بر اساس کیلو بایت برای اضافه شدن به تراکنشی که ارسال کرده اید - + Loading wallet... wallet در حال لود شدن است... - + Cannot downgrade wallet قابلیت برگشت به نسخه قبلی برای wallet امکان پذیر نیست @@ -2857,22 +2890,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. آدرس پیش فرض قابل ذخیره نیست - + Rescanning... اسکنِ دوباره... - + Done loading اتمام لود شدن - + To use the %s option برای استفاده از %s از اختیارات - + Error خطا diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index 70803e7f6..b357e9097 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -2132,6 +2132,14 @@ Osoite: %4 kenelle + + WalletModel + + + Send Coins + Lähetä Bitcoineja + + WalletView @@ -2183,12 +2191,12 @@ Osoite: %4 Bitcoinin versio - + Usage: Käyttö: - + Send command to -server or bitcoind Lähetä käsky palvelimelle tai bitcoind:lle @@ -2198,17 +2206,17 @@ Osoite: %4 Lista komennoista - + Get help for a command Hanki apua käskyyn - + Options: Asetukset: - + Specify configuration file (default: bitcoin.conf) Määritä asetustiedosto (oletus: bitcoin.conf) @@ -2223,7 +2231,7 @@ Osoite: %4 Määritä data-hakemisto - + Set database cache size in megabytes (default: 25) Aseta tietokannan välimuistin koko megatavuina (oletus: 25) @@ -2238,12 +2246,12 @@ Osoite: %4 Pidä enintään <n> yhteyttä verkkoihin (oletus: 125) - + Connect to a node to retrieve peer addresses, and disconnect Yhdistä noodiin hakeaksesi naapurien osoitteet ja katkaise yhteys - + Specify your own public address Määritä julkinen osoitteesi @@ -2253,7 +2261,7 @@ Osoite: %4 Kynnysarvo aikakatkaisulle heikosti toimiville verkoille (oletus: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Sekuntien määrä, kuinka kauan uudelleenkytkeydytään verkkoihin (oletus: 86400) @@ -2273,17 +2281,17 @@ Osoite: %4 Hyväksy merkkipohjaiset- ja JSON-RPC-käskyt - + Run in the background as a daemon and accept commands Aja taustalla daemonina ja hyväksy komennot - + Use the test network Käytä test -verkkoa - + Accept connections from outside (default: 1 if no -proxy or -connect) Hyväksy yhteyksiä ulkopuolelta (vakioasetus: 1 jos -proxy tai -connect ei määritelty) @@ -2427,11 +2435,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Varoitus: Levytila on vähissä! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2518,7 +2521,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2533,7 +2536,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2543,17 +2546,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file Tuodaan lohkoja ulkoisesta blk000??.dat tiedostosta - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Tietoa @@ -2562,6 +2565,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Virheellinen -tor osoite '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2637,6 +2650,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Pienennä debug.log tiedosto käynnistyksen yhteydessä (vakioasetus: 1 kun ei -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2648,7 +2666,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Järjestelmävirhe: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Käytä UPnP:tä kuunneltavan portin avaamiseen (vakioasetus: 0) @@ -2688,32 +2721,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Salasana JSON-RPC-yhteyksille - + Allow JSON-RPC connections from specified IP address Salli JSON-RPC yhteydet tietystä ip-osoitteesta - + Send commands to node running on <ip> (default: 127.0.0.1) Lähetä käskyjä solmuun osoitteessa <ip> (oletus: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Suorita käsky kun paras lohko muuttuu (%s cmd on vaihdettu block hashin kanssa) - + Upgrade wallet to latest format Päivitä lompakko uusimpaan formaattiin - + Set key pool size to <n> (default: 100) Aseta avainpoolin koko arvoon <n> (oletus: 100) @@ -2723,12 +2756,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Skannaa uudelleen lohkoketju lompakon puuttuvien rahasiirtojen vuoksi - + Use OpenSSL (https) for JSON-RPC connections Käytä OpenSSL:ää (https) JSON-RPC-yhteyksille - + Server certificate file (default: server.cert) Palvelimen sertifikaatti-tiedosto (oletus: server.cert) @@ -2738,23 +2771,23 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Palvelimen yksityisavain (oletus: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Hyväksyttävä salaus (oletus: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Tämä ohjeviesti - + Unable to bind to %s on this computer (bind returned error %d, %s) Kytkeytyminen %s tällä tietokonella ei onnistu (kytkeytyminen palautti virheen %d, %s) - + Connect through socks proxy Yhdistä socks proxyn läpi @@ -2764,12 +2797,12 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Salli DNS kyselyt -addnode, -seednode ja -connect yhteydessä - + Loading addresses... Ladataan osoitteita... - + Error loading wallet.dat: Wallet corrupted Virhe ladattaessa wallet.dat-tiedostoa: Lompakko vioittunut @@ -2779,22 +2812,22 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Virhe ladattaessa wallet.dat-tiedostoa: Tarvitset uudemman version Bitcoinista - + Wallet needed to be rewritten: restart Bitcoin to complete Lompakko tarvitsee uudelleenkirjoittaa: käynnistä Bitcoin uudelleen - + Error loading wallet.dat Virhe ladattaessa wallet.dat-tiedostoa - + Invalid -proxy address: '%s' Virheellinen proxy-osoite '%s' - + Unknown network specified in -onlynet: '%s' Tuntematon verkko -onlynet parametrina: '%s' @@ -2804,7 +2837,7 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Tuntematon -socks proxy versio pyydetty: %i - + Cannot resolve -bind address: '%s' -bind osoitteen '%s' selvittäminen epäonnistui @@ -2814,7 +2847,7 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) -externalip osoitteen '%s' selvittäminen epäonnistui - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<amount>: '%s' on virheellinen @@ -2824,17 +2857,17 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Virheellinen määrä - + Insufficient funds Lompakon saldo ei riitä - + Loading block index... Ladataan lohkoindeksiä... - + Add a node to connect to and attempt to keep the connection open Linää solmu mihin liittyä pitääksesi yhteyden auki @@ -2844,17 +2877,17 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Kytkeytyminen %s ei onnistu tällä tietokoneella. Bitcoin on todennäköisesti jo ajamassa. - + Fee per KB to add to transactions you send Rahansiirtopalkkio per KB lisätään lähettämääsi rahansiirtoon - + Loading wallet... Ladataan lompakkoa... - + Cannot downgrade wallet Et voi päivittää lompakkoasi vanhempaan versioon @@ -2864,22 +2897,22 @@ TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Oletusosoitetta ei voi kirjoittaa - + Rescanning... Skannataan uudelleen... - + Done loading Lataus on valmis - + To use the %s option Käytä %s optiota - + Error Virhe diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 33027d3f3..94de09d7f 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -2132,6 +2132,14 @@ Adresse : %4 à + + WalletModel + + + Send Coins + Envoyer des pièces + + WalletView @@ -2183,12 +2191,12 @@ Adresse : %4 Version de Bitcoin - + Usage: Utilisation : - + Send command to -server or bitcoind Envoyer une commande à -server ou à bitcoind @@ -2198,17 +2206,17 @@ Adresse : %4 Lister les commandes - + Get help for a command Obtenir de l’aide pour une commande - + Options: Options : - + Specify configuration file (default: bitcoin.conf) Spécifier le fichier de configuration (par défaut : bitcoin.conf) @@ -2223,7 +2231,7 @@ Adresse : %4 Spécifier le répertoire de données - + Set database cache size in megabytes (default: 25) Définir la taille du tampon en mégaoctets (par défaut : 25) @@ -2238,12 +2246,12 @@ Adresse : %4 Garder au plus <n> connexions avec les pairs (par défaut : 125) - + Connect to a node to retrieve peer addresses, and disconnect Se connecter à un nœud pour obtenir des adresses de pairs puis se déconnecter - + Specify your own public address Spécifier votre propre adresse publique @@ -2253,7 +2261,7 @@ Adresse : %4 Seuil de déconnexion des pairs de mauvaise qualité (par défaut : 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Délai en secondes de refus de reconnexion aux pairs de mauvaise qualité (par défaut : 86400) @@ -2273,17 +2281,17 @@ Adresse : %4 Accepter les commandes de JSON-RPC et de la ligne de commande - + Run in the background as a daemon and accept commands Fonctionner en arrière-plan en tant que démon et accepter les commandes - + Use the test network Utiliser le réseau de test - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepter les connexions entrantes (par défaut : 1 si -proxy ou -connect ne sont pas présents) @@ -2437,11 +2445,6 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Error: Disk space is low! Erreur : l'espace disque est faible ! - - - Error: Transaction creation failed! - Erreur : Échec de la création de la transaction ! - Error: Wallet locked, unable to create transaction! @@ -2528,9 +2531,9 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Niveau d'approfondissement de la vérification des blocs (0-4, par défaut : 3) - + Not enough file descriptors available. - + Pas assez de descripteurs de fichiers disponibles. @@ -2543,7 +2546,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Définir le nombre d'exétrons pour desservir les appels RPC (par défaut : 4) - + Verifying blocks... Vérification des blocs... @@ -2553,17 +2556,17 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Vérification du porte-monnaie... - + Imports blocks from external blk000??.dat file Importe des blocs depuis un fichier blk000??.dat externe - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Définir le nombre de fils d’exécution pour la vérification des scripts (maximum 16, 0 = auto, < 0 = laisser ce nombre de cœurs libres, par défaut : 0) - + Information Informations @@ -2572,6 +2575,16 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Invalid -tor address: '%s' Adresse -tor invalide : « %s » + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Montant invalide pour -minrelayfee=<montant> : « %s » + + + + Invalid amount for -mintxfee=<amount>: '%s' + Montant invalide pour -mintxfee=<montant> : « %s » + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Shrink debug.log file on client startup (default: 1 when no -debug) Réduire le fichier debug.log lors du démarrage du client (par défaut : 1 lorsque -debug n'est pas présent) + + + Signing transaction failed + La signature de la transaction a échoué + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Erreur système : - + + Transaction amount too small + Montant de la transaction trop bas + + + + Transaction amounts must be positive + Les montants de la transaction doivent être positifs + + + + Transaction too large + Transaction trop volumineuse + + + Use UPnP to map the listening port (default: 0) Utiliser l'UPnP pour rediriger le port d'écoute (par défaut : 0) @@ -2698,32 +2731,32 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo wallet.dat corrompu, la récupération a échoué - + Password for JSON-RPC connections Mot de passe pour les connexions JSON-RPC - + Allow JSON-RPC connections from specified IP address Autoriser les connexions JSON-RPC depuis l'adresse IP spécifiée - + Send commands to node running on <ip> (default: 127.0.0.1) Envoyer des commandes au nœud fonctionnant à <ip> (par défaut : 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Exécuter la commande lorsque le meilleur bloc change (%s est remplacé par le hachage du bloc dans cmd) - + Upgrade wallet to latest format Mettre à jour le format du porte-monnaie - + Set key pool size to <n> (default: 100) Régler la taille de la plage de clefs sur <n> (par défaut : 100) @@ -2733,12 +2766,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Réanalyser la chaîne de blocs pour les transactions de porte-monnaie manquantes - + Use OpenSSL (https) for JSON-RPC connections Utiliser OpenSSL (https) pour les connexions JSON-RPC - + Server certificate file (default: server.cert) Fichier de certificat serveur (par défaut : server.cert) @@ -2748,22 +2781,22 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Clef privée du serveur (par défaut : server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Clefs de chiffrement acceptables (par défaut : TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ce message d'aide - + Unable to bind to %s on this computer (bind returned error %d, %s) Impossible de se lier à %s sur cet ordinateur (bind a retourné l'erreur %d, %s) - + Connect through socks proxy Connexion via un proxy socks @@ -2773,12 +2806,12 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Autoriser les recherches DNS pour -addnode, -seednode et -connect - + Loading addresses... Chargement des adresses… - + Error loading wallet.dat: Wallet corrupted Erreur lors du chargement de wallet.dat : porte-monnaie corrompu @@ -2788,22 +2821,22 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Erreur lors du chargement de wallet.dat : le porte-monnaie nécessite une version plus récente de Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Le porte-monnaie nécessitait une réécriture : veuillez redémarrer Bitcoin pour terminer l'opération - + Error loading wallet.dat Erreur lors du chargement de wallet.dat - + Invalid -proxy address: '%s' Adresse -proxy invalide : « %s » - + Unknown network specified in -onlynet: '%s' Réseau inconnu spécifié sur -onlynet : « %s » @@ -2813,7 +2846,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Version inconnue de proxy -socks demandée : %i - + Cannot resolve -bind address: '%s' Impossible de résoudre l'adresse -bind : « %s » @@ -2823,7 +2856,7 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Impossible de résoudre l'adresse -externalip : « %s » - + Invalid amount for -paytxfee=<amount>: '%s' Montant invalide pour -paytxfee=<montant> : « %s » @@ -2833,17 +2866,17 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Montant invalide - + Insufficient funds Fonds insuffisants - + Loading block index... Chargement de l’index des blocs… - + Add a node to connect to and attempt to keep the connection open Ajouter un nœud auquel se connecter et tenter de garder la connexion ouverte @@ -2853,17 +2886,17 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Impossible de se lier à %s sur cet ordinateur. Bitcoin fonctionne probablement déjà. - + Fee per KB to add to transactions you send Frais par Ko à ajouter aux transactions que vous enverrez - + Loading wallet... Chargement du porte-monnaie… - + Cannot downgrade wallet Impossible de revenir à une version antérieure du porte-monnaie @@ -2873,22 +2906,22 @@ par exemple : alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Impossible d'écrire l'adresse par défaut - + Rescanning... Nouvelle analyse… - + Done loading Chargement terminé - + To use the %s option Pour utiliser l'option %s - + Error Erreur diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index 1dddf75bf..12909b42f 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -2128,6 +2128,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2179,12 +2187,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2194,17 +2202,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2219,7 +2227,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2234,12 +2242,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2249,7 +2257,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2269,17 +2277,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2423,11 +2431,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2514,7 +2517,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2529,7 +2532,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2539,17 +2542,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2558,6 +2561,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2633,6 +2646,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2644,7 +2662,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2684,32 +2717,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2719,12 +2752,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2734,22 +2767,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2759,12 +2792,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2774,22 +2807,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2799,7 +2832,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2809,7 +2842,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2819,17 +2852,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2839,17 +2872,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2859,22 +2892,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts index 2b930a4aa..c9ad0e6af 100644 --- a/src/qt/locale/bitcoin_gu_IN.ts +++ b/src/qt/locale/bitcoin_gu_IN.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 499daf100..5fa577faf 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -2131,6 +2131,14 @@ Address: %4 אל + + WalletModel + + + Send Coins + שלח מטבעות + + WalletView @@ -2182,12 +2190,12 @@ Address: %4 גרסת ביטקוין - + Usage: שימוש: - + Send command to -server or bitcoind שלח פקודה ל -server או bitcoind @@ -2197,17 +2205,17 @@ Address: %4 רשימת פקודות - + Get help for a command קבל עזרה עבור פקודה - + Options: אפשרויות: - + Specify configuration file (default: bitcoin.conf) ציין קובץ הגדרות (ברירת מחדל: bitcoin.conf) @@ -2222,7 +2230,7 @@ Address: %4 ציין תיקיית נתונים - + Set database cache size in megabytes (default: 25) קבע את גודל המטמון של מסד הנתונים במגהבייט (ברירת מחדל: 25) @@ -2237,12 +2245,12 @@ Address: %4 החזק לכל היותר <n> חיבורים לעמיתים (ברירת מחדל: 125) - + Connect to a node to retrieve peer addresses, and disconnect התחבר לצומת כדי לדלות כתובות עמיתים, ואז התנתק - + Specify your own public address ציין את הכתובת הפומבית שלך @@ -2252,7 +2260,7 @@ Address: %4 סף להתנתקות מעמיתים הנוהגים שלא כהלכה (ברירת מחדל: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) מספר שניות למנוע מעמיתים הנוהגים שלא כהלכה מלהתחבר מחדש (ברירת מחדל: 86400) @@ -2272,17 +2280,17 @@ Address: %4 קבל פקודות משורת הפקודה ו- JSON-RPC - + Run in the background as a daemon and accept commands רוץ ברקע כדימון וקבל פקודות - + Use the test network השתמש ברשת הבדיקה - + Accept connections from outside (default: 1 if no -proxy or -connect) קבל חיבורים מבחוץ (ברירת מחדל: 1 ללא -proxy או -connect) @@ -2436,11 +2444,6 @@ rpcpassword=%s Error: Disk space is low! שגיאה: מעט מקום פנוי בדיסק! - - - Error: Transaction creation failed! - שגיאה: יצירת הפעולה נכשלה! - Error: Wallet locked, unable to create transaction! @@ -2527,7 +2530,7 @@ rpcpassword=%s מידת היסודיות של אימות הבלוקים (0-4, ברירת מחדל: 3) - + Not enough file descriptors available. @@ -2542,7 +2545,7 @@ rpcpassword=%s קבע את מספר תהליכוני לשירות קריאות RPC (ברירת מחדל: 4) - + Verifying blocks... מאמת את שלמות מסד הנתונים... @@ -2552,17 +2555,17 @@ rpcpassword=%s מאמת את יושרת הארנק... - + Imports blocks from external blk000??.dat file מייבא בלוקים מקובצי blk000??.dat חיצוניים - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information מידע @@ -2571,6 +2574,16 @@ rpcpassword=%s Invalid -tor address: '%s' כתובת לא תקינה ל -tor: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2646,6 +2659,11 @@ rpcpassword=%s Shrink debug.log file on client startup (default: 1 when no -debug) כווץ את קובץ debug.log בהפעלת הקליינט (ברירת מחדל: 1 ללא -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2657,7 +2675,22 @@ rpcpassword=%s שגיאת מערכת: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) השתמש ב-UPnP כדי למפות את הפורט להאזנה (ברירת מחדל: 0) @@ -2697,32 +2730,32 @@ rpcpassword=%s קובץ wallet.dat מושחת, החילוץ נכשל - + Password for JSON-RPC connections סיסמה לחיבורי JSON-RPC - + Allow JSON-RPC connections from specified IP address אפשר חיבורי JSON-RPC מכתובת האינטרנט המצוינת - + Send commands to node running on <ip> (default: 127.0.0.1) שלח פקודות לצומת ב-<ip> (ברירת מחדל: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) בצע פקודה זו כשהבלוק הטוב ביותר משתנה (%s בפקודה יוחלף בגיבוב הבלוק) - + Upgrade wallet to latest format שדרג את הארנק לפורמט העדכני - + Set key pool size to <n> (default: 100) קבע את גודל המאגר ל -<n> (ברירת מחדל: 100) @@ -2732,12 +2765,12 @@ rpcpassword=%s סרוק מחדש את שרשרת הבלוקים למציאת פעולות חסרות בארנק - + Use OpenSSL (https) for JSON-RPC connections השתמש ב-OpenSSL (https( עבור חיבורי JSON-RPC - + Server certificate file (default: server.cert) קובץ תעודת שרת (ברירת מחדל: server.cert) @@ -2747,22 +2780,22 @@ rpcpassword=%s מפתח פרטי של השרת (ברירת מחדל: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) צפנים קבילים (ברירת מחדל: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message הודעת העזרה הזו - + Unable to bind to %s on this computer (bind returned error %d, %s) לא מסוגל לקשור ל-%s במחשב זה (הקשירה החזירה שגיאה %d, %s) - + Connect through socks proxy התחבר דרך פרוקסי SOCKS @@ -2772,12 +2805,12 @@ rpcpassword=%s אפשר בדיקת DNS עבור -addnode, -seednode ו- -connect - + Loading addresses... טוען כתובות... - + Error loading wallet.dat: Wallet corrupted שגיאה בטעינת הקובץ wallet.dat: הארנק מושחת @@ -2787,22 +2820,22 @@ rpcpassword=%s שגיאה בטעינת הקובץ wallet.dat: הארנק דורש גרסה חדשה יותר של ביטקוין - + Wallet needed to be rewritten: restart Bitcoin to complete יש לכתוב מחדש את הארנק: אתחל את ביטקוין לסיום - + Error loading wallet.dat שגיאה בטעינת הקובץ wallet.dat - + Invalid -proxy address: '%s' כתובת -proxy לא תקינה: '%s' - + Unknown network specified in -onlynet: '%s' רשת לא ידועה צוינה ב- -onlynet: '%s' @@ -2812,7 +2845,7 @@ rpcpassword=%s התבקשה גרסת פרוקסי -socks לא ידועה: %i - + Cannot resolve -bind address: '%s' לא מסוגל לפתור כתובת -bind: '%s' @@ -2822,7 +2855,7 @@ rpcpassword=%s לא מסוגל לפתור כתובת -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' כמות לא תקינה עבור -paytxfee=<amount>: '%s' @@ -2832,17 +2865,17 @@ rpcpassword=%s כמות לא תקינה - + Insufficient funds אין מספיק כספים - + Loading block index... טוען את אינדקס הבלוקים... - + Add a node to connect to and attempt to keep the connection open הוסף צומת להתחברות ונסה לשמור את החיבור פתוח @@ -2852,17 +2885,17 @@ rpcpassword=%s לא ניתן לקשור ל-%s במחשב זה. ביטקוין כנראה עדיין רץ. - + Fee per KB to add to transactions you send עמלה להוסיף לפעולות שאתה שולח עבור כל KB - + Loading wallet... טוען ארנק... - + Cannot downgrade wallet לא יכול להוריד דרגת הארנק @@ -2872,22 +2905,22 @@ rpcpassword=%s לא יכול לכתוב את כתובת ברירת המחדל - + Rescanning... סורק מחדש... - + Done loading טעינה הושלמה - + To use the %s option להשתמש באפשרות %s - + Error שגיאה diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index 1c38925d0..f49e0e38a 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -2128,6 +2128,14 @@ Address: %4 तक + + WalletModel + + + Send Coins + + + WalletView @@ -2179,12 +2187,12 @@ Address: %4 बीटकोइन संस्करण - + Usage: खपत : - + Send command to -server or bitcoind -server या bitcoind को कमांड भेजें @@ -2194,17 +2202,17 @@ Address: %4 commands की लिस्ट बनाएं - + Get help for a command किसी command के लिए मदद लें - + Options: विकल्प: - + Specify configuration file (default: bitcoin.conf) configuraion की फाइल का विवरण दें (default: bitcoin.conf) @@ -2219,7 +2227,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2234,12 +2242,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2249,7 +2257,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2269,17 +2277,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2423,11 +2431,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2514,7 +2517,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2529,7 +2532,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... ब्लॉक्स जाँचे जा रहा है... @@ -2539,17 +2542,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. वॉलेट जाँचा जा रहा है... - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information जानकारी @@ -2558,6 +2561,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2633,6 +2646,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2644,7 +2662,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2684,32 +2717,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2719,12 +2752,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2734,22 +2767,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2759,12 +2792,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... पता पुस्तक आ रही है... - + Error loading wallet.dat: Wallet corrupted @@ -2774,22 +2807,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2799,7 +2832,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2809,7 +2842,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2819,17 +2852,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. राशि ग़लत है - + Insufficient funds - + Loading block index... ब्लॉक इंडेक्स आ रहा है... - + Add a node to connect to and attempt to keep the connection open @@ -2839,17 +2872,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... वॉलेट आ रहा है... - + Cannot downgrade wallet @@ -2859,22 +2892,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... रि-स्केनी-इंग... - + Done loading लोड हो गया| - + To use the %s option - + Error भूल diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index ef8b2b759..f0cd94fa5 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -2127,6 +2127,14 @@ Adresa:%4 za + + WalletModel + + + Send Coins + Slanje novca + + WalletView @@ -2178,12 +2186,12 @@ Adresa:%4 Bitcoin verzija - + Usage: Upotreba: - + Send command to -server or bitcoind Pošalji komandu usluzi -server ili bitcoind @@ -2193,17 +2201,17 @@ Adresa:%4 Prikaži komande - + Get help for a command Potraži pomoć za komandu - + Options: Postavke: - + Specify configuration file (default: bitcoin.conf) Odredi konfiguracijsku datoteku (ugrađeni izbor: bitcoin.conf) @@ -2218,7 +2226,7 @@ Adresa:%4 Odredi direktorij za datoteke - + Set database cache size in megabytes (default: 25) Postavi cache za bazu podataka u MB (zadano:25) @@ -2233,12 +2241,12 @@ Adresa:%4 Održavaj najviše <n> veza sa članovima (default: 125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2248,7 +2256,7 @@ Adresa:%4 Prag za odspajanje članova koji se čudno ponašaju (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Broj sekundi koliko se članovima koji se čudno ponašaju neće dopustiti da se opet spoje (default: 86400) @@ -2268,17 +2276,17 @@ Adresa:%4 Prihvati komande iz tekst moda i JSON-RPC - + Run in the background as a daemon and accept commands Izvršavaj u pozadini kao uslužnik i prihvaćaj komande - + Use the test network Koristi test mrežu - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2422,11 +2430,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2513,7 +2516,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2528,7 +2531,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2538,17 +2541,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file Importiraj blokove sa vanjskog blk000??.dat fajla - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2557,6 +2560,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Nevaljala -tor adresa: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2632,6 +2645,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2643,7 +2661,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Pokušaj koristiti UPnP da otvoriš port za uslugu (default: 0) @@ -2683,32 +2716,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Lozinka za JSON-RPC veze - + Allow JSON-RPC connections from specified IP address Dozvoli JSON-RPC povezivanje s određene IP adrese - + Send commands to node running on <ip> (default: 127.0.0.1) Pošalji komande nodu na adresi <ip> (ugrađeni izbor: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Izvršite naredbu kada se najbolji blok promjeni (%s u cmd je zamjenjen sa block hash) - + Upgrade wallet to latest format Nadogradite novčanik u posljednji format. - + Set key pool size to <n> (default: 100) Podesi memorijski prostor za ključeve na <n> (ugrađeni izbor: 100) @@ -2718,12 +2751,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ponovno pretraži lanac blokova za transakcije koje nedostaju - + Use OpenSSL (https) for JSON-RPC connections Koristi OpenSSL (https) za JSON-RPC povezivanje - + Server certificate file (default: server.cert) Uslužnikov SSL certifikat (ugrađeni izbor: server.cert) @@ -2733,22 +2766,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Uslužnikov privatni ključ (ugrađeni izbor: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Prihvaljivi načini šifriranja (ugrađeni izbor: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ova poruka za pomoć - + Unable to bind to %s on this computer (bind returned error %d, %s) Program ne može koristiti %s na ovom računalu (bind returned error %d, %s) - + Connect through socks proxy Poveži se kroz socks proxy @@ -2758,12 +2791,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Dozvoli DNS upite za dodavanje nodova i povezivanje - + Loading addresses... Učitavanje adresa... - + Error loading wallet.dat: Wallet corrupted Greška kod učitavanja wallet.dat: Novčanik pokvaren @@ -2773,22 +2806,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Greška kod učitavanja wallet.dat: Novčanik zahtjeva noviju verziju Bitcoina - + Wallet needed to be rewritten: restart Bitcoin to complete Novčanik je trebao prepravak: ponovo pokrenite Bitcoin - + Error loading wallet.dat Greška kod učitavanja wallet.dat - + Invalid -proxy address: '%s' Nevaljala -proxy adresa: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2798,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2808,7 +2841,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Nevaljali iznos za opciju -paytxfee=<amount>: '%s' @@ -2818,17 +2851,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevaljali iznos za opciju - + Insufficient funds Nedovoljna sredstva - + Loading block index... Učitavanje indeksa blokova... - + Add a node to connect to and attempt to keep the connection open Unesite nod s kojim se želite spojiti and attempt to keep the connection open @@ -2838,17 +2871,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Program ne može koristiti %s na ovom računalu. Bitcoin program je vjerojatno već pokrenut. - + Fee per KB to add to transactions you send Naknada posredniku po KB-u koja će biti dodana svakoj transakciji koju pošalješ - + Loading wallet... Učitavanje novčanika... - + Cannot downgrade wallet Nije moguće novčanik vratiti na prijašnju verziju. @@ -2858,22 +2891,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nije moguće upisati zadanu adresu. - + Rescanning... Rescaniranje - + Done loading Učitavanje gotovo - + To use the %s option - + Error Greška diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index 3f0e6b955..ce43e9145 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -2133,6 +2133,14 @@ Cím: %4 meddig + + WalletModel + + + Send Coins + Érmék küldése + + WalletView @@ -2184,12 +2192,12 @@ Cím: %4 Bitcoin verzió - + Usage: Használat: - + Send command to -server or bitcoind Parancs küldése a -serverhez vagy a bitcoindhez @@ -2201,19 +2209,19 @@ Cím: %4 - + Get help for a command Segítség egy parancsról - + Options: Opciók - + Specify configuration file (default: bitcoin.conf) Konfigurációs fájl (alapértelmezett: bitcoin.conf) @@ -2231,7 +2239,7 @@ Cím: %4 - + Set database cache size in megabytes (default: 25) Az adatbázis gyorsítótár mérete megabájtban (alapértelmezés: 25) @@ -2246,12 +2254,12 @@ Cím: %4 Maximálisan <n> számú kapcsolat fenntartása a peerekkel (alapértelmezés: 125) - + Connect to a node to retrieve peer addresses, and disconnect Kapcsolódás egy csomóponthoz a peerek címeinek megszerzése miatt, majd szétkapcsolás - + Specify your own public address Adja meg az Ön saját nyilvános címét @@ -2261,7 +2269,7 @@ Cím: %4 Helytelenül viselkedő peerek leválasztási határértéke (alapértelmezés: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Helytelenül viselkedő peerek kizárási ideje másodpercben (alapértelmezés: 86400) @@ -2282,19 +2290,19 @@ Cím: %4 - + Run in the background as a daemon and accept commands Háttérben futtatás daemonként és parancsok elfogadása - + Use the test network Teszthálózat használata - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2438,11 +2446,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2529,7 +2532,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2544,7 +2547,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2554,17 +2557,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2573,6 +2576,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Érvénytelen -tor cím: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2648,6 +2661,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2659,7 +2677,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 0) @@ -2700,35 +2733,35 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Jelszó JSON-RPC csatlakozásokhoz - + Allow JSON-RPC connections from specified IP address JSON-RPC csatlakozások engedélyezése meghatározott IP-címről - + Send commands to node running on <ip> (default: 127.0.0.1) Parancsok küldése <ip> címen működő csomóponthoz (alapértelmezett: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Parancs, amit akkor hajt végre, amikor a legjobb blokk megváltozik (%s a cmd-ban lecserélődik a blokk hash-re) - + Upgrade wallet to latest format A Tárca frissítése a legfrissebb formátumra - + Set key pool size to <n> (default: 100) Kulcskarika mérete <n> (alapértelmezett: 100) @@ -2740,13 +2773,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections OpenSSL (https) használata JSON-RPC csatalkozásokhoz - + Server certificate file (default: server.cert) Szervertanúsítvány-fájl (alapértelmezett: server.cert) @@ -2758,24 +2791,24 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Elfogadható rejtjelkulcsok (alapértelmezett: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH ) - + This help message Ez a súgó-üzenet - + Unable to bind to %s on this computer (bind returned error %d, %s) A %s nem elérhető ezen a gépen (bind returned error %d, %s) - + Connect through socks proxy Csatlakozás SOCKS proxyn keresztül @@ -2785,12 +2818,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. DNS-kikeresés engedélyezése az addnode-nál és a connect-nél - + Loading addresses... Címek betöltése... - + Error loading wallet.dat: Wallet corrupted Hiba a wallet.dat betöltése közben: meghibásodott tárca @@ -2800,22 +2833,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Hiba a wallet.dat betöltése közben: ehhez a tárcához újabb verziójú Bitcoin-kliens szükséges - + Wallet needed to be rewritten: restart Bitcoin to complete A Tárca újraírása szükséges: Indítsa újra a teljesen a Bitcoin-t - + Error loading wallet.dat Hiba az wallet.dat betöltése közben - + Invalid -proxy address: '%s' Érvénytelen -proxy cím: '%s' - + Unknown network specified in -onlynet: '%s' Ismeretlen hálózat lett megadva -onlynet: '%s' @@ -2825,7 +2858,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ismeretlen -socks proxy kérése: %i - + Cannot resolve -bind address: '%s' @@ -2835,7 +2868,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Étvénytelen -paytxfee=<összeg> összeg: '%s' @@ -2845,17 +2878,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Étvénytelen összeg - + Insufficient funds Nincs elég bitcoinod. - + Loading block index... Blokkindex betöltése... - + Add a node to connect to and attempt to keep the connection open Elérendő csomópont megadása and attempt to keep the connection open @@ -2865,17 +2898,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. A %s nem elérhető ezen a gépen. A Bitcoin valószínűleg fut már. - + Fee per KB to add to transactions you send kB-onként felajánlandó díj az általad küldött tranzakciókhoz - + Loading wallet... Tárca betöltése... - + Cannot downgrade wallet Nem sikerült a Tárca visszaállítása a korábbi verzióra @@ -2885,22 +2918,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nem sikerült az alapértelmezett címet írni. - + Rescanning... Újraszkennelés... - + Done loading Betöltés befejezve. - + To use the %s option Használd a %s opciót - + Error Hiba diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index b634486e2..48c03d6dc 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -2134,6 +2134,14 @@ Indirizzo: %4 a + + WalletModel + + + Send Coins + Spedisci Bitcoin + + WalletView @@ -2185,12 +2193,12 @@ Indirizzo: %4 Versione di Bitcoin - + Usage: Utilizzo: - + Send command to -server or bitcoind Manda il comando a -server o bitcoind @@ -2202,19 +2210,19 @@ Indirizzo: %4 - + Get help for a command Aiuto su un comando - + Options: Opzioni: - + Specify configuration file (default: bitcoin.conf) Specifica il file di configurazione (di default: bitcoin.conf) @@ -2232,7 +2240,7 @@ Indirizzo: %4 - + Set database cache size in megabytes (default: 25) Imposta la dimensione cache del database in megabyte (default: 25) @@ -2247,12 +2255,12 @@ Indirizzo: %4 Mantieni al massimo <n> connessioni ai peer (default: 125) - + Connect to a node to retrieve peer addresses, and disconnect Connessione ad un nodo per ricevere l'indirizzo del peer, e disconnessione - + Specify your own public address Specifica il tuo indirizzo pubblico @@ -2262,7 +2270,7 @@ Indirizzo: %4 Soglia di disconnessione dei peer di cattiva qualità (default: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Numero di secondi di sospensione che i peer di cattiva qualità devono trascorrere prima di riconnettersi (default: 86400) @@ -2283,19 +2291,19 @@ Indirizzo: %4 - + Run in the background as a daemon and accept commands Esegui in background come demone e accetta i comandi - + Use the test network Utilizza la rete di prova - + Accept connections from outside (default: 1 if no -proxy or -connect) Accetta connessioni dall'esterno (default: 1 se no -proxy o -connect) @@ -2439,11 +2447,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Errore: la spazio libero sul disco è poco! - - - Error: Transaction creation failed! - Errore: Creazione transazione fallita! - Error: Wallet locked, unable to create transaction! @@ -2530,7 +2533,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2545,7 +2548,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... Verifica blocchi... @@ -2555,17 +2558,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verifica portafoglio... - + Imports blocks from external blk000??.dat file Importa blocchi da un file blk000??.dat esterno - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Informazione @@ -2574,6 +2577,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Indirizzo -tor non valido: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2649,6 +2662,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Riduci il file debug.log all'avvio del client (predefinito: 1 se non impostato -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2660,7 +2678,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Errore di sistema: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) UPnP-használat engedélyezése a figyelő port feltérképezésénél (default: 0) @@ -2701,35 +2734,35 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat corrotto, salvataggio fallito - + Password for JSON-RPC connections Password per connessioni JSON-RPC - + Allow JSON-RPC connections from specified IP address Consenti connessioni JSON-RPC dall'indirizzo IP specificato - + Send commands to node running on <ip> (default: 127.0.0.1) Inviare comandi al nodo in esecuzione su <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Esegui il comando quando il miglior block cambia(%s nel cmd è sostituito dall'hash del blocco) - + Upgrade wallet to latest format Aggiorna il wallet all'ultimo formato - + Set key pool size to <n> (default: 100) Impostare la quantità di chiavi di riserva a <n> (default: 100) @@ -2741,13 +2774,13 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections Utilizzare OpenSSL (https) per le connessioni JSON-RPC - + Server certificate file (default: server.cert) File certificato del server (default: server.cert) @@ -2759,24 +2792,24 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifrari accettabili (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Questo messaggio di aiuto - + Unable to bind to %s on this computer (bind returned error %d, %s) Impossibile collegarsi alla %s su questo computer (bind returned error %d, %s) - + Connect through socks proxy Connessione tramite socks proxy @@ -2787,12 +2820,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... Caricamento indirizzi... - + Error loading wallet.dat: Wallet corrupted Errore caricamento wallet.dat: Wallet corrotto @@ -2802,22 +2835,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Errore caricamento wallet.dat: il wallet richiede una versione nuova di Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Il portamonete deve essere riscritto: riavviare Bitcoin per completare - + Error loading wallet.dat Errore caricamento wallet.dat - + Invalid -proxy address: '%s' Indirizzo -proxy non valido: '%s' - + Unknown network specified in -onlynet: '%s' Rete sconosciuta specificata in -onlynet: '%s' @@ -2827,7 +2860,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Versione -socks proxy sconosciuta richiesta: %i - + Cannot resolve -bind address: '%s' Impossibile risolvere -bind address: '%s' @@ -2837,7 +2870,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossibile risolvere indirizzo -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Importo non valido per -paytxfee=<amount>: '%s' @@ -2847,17 +2880,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Importo non valido - + Insufficient funds Fondi insufficienti - + Loading block index... Caricamento dell'indice del blocco... - + Add a node to connect to and attempt to keep the connection open Elérendő csomópont megadása and attempt to keep the connection open @@ -2867,17 +2900,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossibile collegarsi alla %s su questo computer. Probabilmente Bitcoin è già in esecuzione. - + Fee per KB to add to transactions you send Commissione per KB da aggiungere alle transazioni in uscita - + Loading wallet... Caricamento portamonete... - + Cannot downgrade wallet Non è possibile retrocedere il wallet @@ -2887,22 +2920,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Non è possibile scrivere l'indirizzo di default - + Rescanning... Ripetere la scansione... - + Done loading Caricamento completato - + To use the %s option Per usare la opzione %s - + Error Errore diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index 18a663540..93ac949e7 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 Bitcoin Bertsio - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index f92c3daf6..f444d461f 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -2131,6 +2131,14 @@ Inscriptio: %4 ad + + WalletModel + + + Send Coins + + + WalletView @@ -2182,12 +2190,12 @@ Inscriptio: %4 Versio de Bitcoin - + Usage: Usus: - + Send command to -server or bitcoind Mitte mandatum ad -server vel bitcoind @@ -2197,17 +2205,17 @@ Inscriptio: %4 Enumera mandata - + Get help for a command Accipe auxilium pro mandato - + Options: Optiones: - + Specify configuration file (default: bitcoin.conf) Specifica configurationis plicam (praedefinitum: bitcoin.conf) @@ -2222,7 +2230,7 @@ Inscriptio: %4 Specifica indicem datorum - + Set database cache size in megabytes (default: 25) Constitue magnitudinem databasis cache in megabytes (praedefinitum: 25) @@ -2237,12 +2245,12 @@ Inscriptio: %4 Manutene non plures quam <n> conexiones ad paria (praedefinitum: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conecta ad nodum acceptare inscriptiones parium, et disconecte - + Specify your own public address Specifica tuam propriam publicam inscriptionem @@ -2252,7 +2260,7 @@ Inscriptio: %4 Limen pro disconectendo paria improba (praedefinitum: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Numerum secundorum prohibere ne paria improba reconectant (praedefinitum: 86400) @@ -2272,17 +2280,17 @@ Inscriptio: %4 Accipe terminalis et JSON-RPC mandata. - + Run in the background as a daemon and accept commands Operare infere sicut daemon et mandata accipe - + Use the test network Utere rete experimentale - + Accept connections from outside (default: 1 if no -proxy or -connect) Accipe conexiones externas (praedefinitum: 1 nisi -proxy neque -connect) @@ -2436,11 +2444,6 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Error: Disk space is low! Error: Inopia spatii disci! - - - Error: Transaction creation failed! - Error: Creare transactionum abortum est! - Error: Wallet locked, unable to create transaction! @@ -2527,7 +2530,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Quam perfecta frustorum verificatio est (0-4, praedefinitum: 3) - + Not enough file descriptors available. @@ -2542,7 +2545,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Constitue numerum filorum ad tractandum RPC postulationes (praedefinitum: 4) - + Verifying blocks... Verificante frusta... @@ -2552,17 +2555,17 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Verificante cassidilem... - + Imports blocks from external blk000??.dat file Importat frusta ab externa plica blk000??.dat - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Informatio @@ -2571,6 +2574,16 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Invalid -tor address: '%s' Inscriptio -tor non valida: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2646,6 +2659,11 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Shrink debug.log file on client startup (default: 1 when no -debug) Diminue plicam debug.log ad initium clientis (praedefinitum: 1 nisi -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2657,7 +2675,22 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Systematis error: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Utere UPnP designare portam auscultandi (praedefinitum: 0) @@ -2697,32 +2730,32 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a wallet.dat corrupta, salvare abortum est - + Password for JSON-RPC connections Tessera pro conexionibus JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitte conexionibus JSON-RPC ex inscriptione specificata - + Send commands to node running on <ip> (default: 127.0.0.1) Mitte mandata nodo operanti in <ip> (praedefinitum: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Pelle mandatum quando optissimum frustum mutat (%s in mandato substituitur ab hash frusti) - + Upgrade wallet to latest format Progredere cassidile ad formam recentissimam - + Set key pool size to <n> (default: 100) Constitue magnitudinem stagni clavium ad <n> (praedefinitum: 100) @@ -2732,12 +2765,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Iterum perlege catenam frustorum propter absentes cassidilis transactiones - + Use OpenSSL (https) for JSON-RPC connections Utere OpenSSL (https) pro conexionibus JSON-RPC - + Server certificate file (default: server.cert) Plica certificationis daemonis moderantis (praedefinitum: server.cert) @@ -2747,22 +2780,22 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Clavis privata daemonis moderans (praedefinitum: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Acceptabiles cifrae (praedefinitum: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Hic nuntius auxilii - + Unable to bind to %s on this computer (bind returned error %d, %s) Non posse conglutinare ad %s in hoc computatro (conglutinare redidit errorem %d, %s) - + Connect through socks proxy Conecte per socks vicarium @@ -2772,12 +2805,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Permitte quaerenda DNS pro -addnode, -seednode, et -connect - + Loading addresses... Legens inscriptiones... - + Error loading wallet.dat: Wallet corrupted Error legendi wallet.dat: Cassidile corruptum @@ -2787,22 +2820,22 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Error legendi wallet.dat: Cassidili necesse est recentior versio Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Cassidili necesse erat rescribi: Repelle Bitcoin ut compleas - + Error loading wallet.dat Error legendi wallet.dat - + Invalid -proxy address: '%s' Inscriptio -proxy non valida: '%s' - + Unknown network specified in -onlynet: '%s' Ignotum rete specificatum in -onlynet: '%s' @@ -2812,7 +2845,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Ignota -socks vicarii versio postulata: %i - + Cannot resolve -bind address: '%s' Non posse resolvere -bind inscriptonem: '%s' @@ -2822,7 +2855,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Non posse resolvere -externalip inscriptionem: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantitas non valida pro -paytxfee=<quantitas>: '%s' @@ -2832,17 +2865,17 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Quantitas non valida - + Insufficient funds Inopia nummorum - + Loading block index... Legens indicem frustorum... - + Add a node to connect to and attempt to keep the connection open Adice nodum cui conectere et conare sustinere conexionem apertam @@ -2852,17 +2885,17 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Non posse conglutinare ad %s in hoc cumputatro. Bitcoin probabiliter iam operatur. - + Fee per KB to add to transactions you send Merces per KB addere ad transactiones tu mittas - + Loading wallet... Legens cassidile... - + Cannot downgrade wallet Non posse cassidile regredi @@ -2872,22 +2905,22 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Non posse scribere praedefinitam inscriptionem - + Rescanning... Iterum perlegens... - + Done loading Completo lengendi - + To use the %s option Ut utaris optione %s - + Error Error diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 99c82f549..1ba4b63e1 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -2130,6 +2130,14 @@ Adresas: %4 skirta + + WalletModel + + + Send Coins + Siųsti monetas + + WalletView @@ -2181,12 +2189,12 @@ Adresas: %4 Bitcoin versija - + Usage: Naudojimas: - + Send command to -server or bitcoind Siųsti komandą serveriui arba bitcoind @@ -2196,17 +2204,17 @@ Adresas: %4 Komandų sąrašas - + Get help for a command Suteikti pagalba komandai - + Options: Parinktys: - + Specify configuration file (default: bitcoin.conf) Nurodyti konfigūracijos failą (pagal nutylėjimąt: bitcoin.conf) @@ -2221,7 +2229,7 @@ Adresas: %4 Nustatyti duomenų aplanką - + Set database cache size in megabytes (default: 25) @@ -2236,12 +2244,12 @@ Adresas: %4 Palaikyti ne daugiau <n> jungčių kolegoms (pagal nutylėjimą: 125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2251,7 +2259,7 @@ Adresas: %4 Atjungimo dėl netinkamo kolegų elgesio riba (pagal nutylėjimą: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Sekundžių kiekis eikiamas palaikyti ryšį dėl lygiarangių nestabilumo (pagal nutylėjimą: 86.400) @@ -2271,17 +2279,17 @@ Adresas: %4 Priimti komandinę eilutę ir JSON-RPC komandas - + Run in the background as a daemon and accept commands Dirbti fone kaip šešėlyje ir priimti komandas - + Use the test network Naudoti testavimo tinklą - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2425,11 +2433,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2516,7 +2519,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2531,7 +2534,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2541,17 +2544,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2560,6 +2563,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Neteisingas tor adresas: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2635,6 +2648,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2646,7 +2664,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Bandymas naudoti UPnP struktūra klausymosi prievadui (default: 0) @@ -2686,32 +2719,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Slaptažodis JSON-RPC sujungimams - + Allow JSON-RPC connections from specified IP address Leisti JSON-RPC tik iš nurodytų IP adresų - + Send commands to node running on <ip> (default: 127.0.0.1) Siųsti komandą mazgui dirbančiam <ip> (pagal nutylėjimą: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format Atnaujinti piniginę į naujausią formatą - + Set key pool size to <n> (default: 100) Nustatyti rakto apimties dydį <n> (pagal nutylėjimą: 100) @@ -2721,12 +2754,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ieškoti prarastų piniginės sandorių blokų grandinėje - + Use OpenSSL (https) for JSON-RPC connections Naudoti OpenSSL (https) jungimuisi JSON-RPC - + Server certificate file (default: server.cert) Serverio sertifikato failas (pagal nutylėjimą: server.cert) @@ -2736,22 +2769,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Serverio privatus raktas (pagal nutylėjimą: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Priimtini šifrai (pagal nutylėjimą: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Pagelbos žinutė - + Unable to bind to %s on this computer (bind returned error %d, %s) Nepavyko susieti šiame kompiuteryje prievado %s (bind returned error %d, %s) - + Connect through socks proxy Jungtis per socks tarpinį serverį @@ -2761,12 +2794,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Leisti DNS paiešką sujungimui ir mazgo pridėjimui - + Loading addresses... Užkraunami adresai... - + Error loading wallet.dat: Wallet corrupted wallet.dat pakrovimo klaida, wallet.dat sugadintas @@ -2776,22 +2809,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat pakrovimo klaida, wallet.dat reikalauja naujasnės Bitcoin versijos - + Wallet needed to be rewritten: restart Bitcoin to complete Piniginė turi būti prrašyta: įvykdymui perkraukite Bitcoin - + Error loading wallet.dat wallet.dat pakrovimo klaida - + Invalid -proxy address: '%s' Neteisingas proxy adresas: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2801,7 +2834,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2811,7 +2844,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Neteisinga suma -paytxfee=<amount>: '%s' @@ -2821,17 +2854,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Neteisinga suma - + Insufficient funds Nepakanka lėšų - + Loading block index... Įkeliamas blokų indeksas... - + Add a node to connect to and attempt to keep the connection open Pridėti mazgą prie sujungti su and attempt to keep the connection open @@ -2841,17 +2874,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nepavyko susieti šiame kompiuteryje prievado %s. Bitcoin tikriausiai jau veikia. - + Fee per KB to add to transactions you send Įtraukti mokestį už kB siunčiamiems sandoriams - + Loading wallet... Užkraunama piniginė... - + Cannot downgrade wallet @@ -2861,22 +2894,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... Peržiūra - + Done loading Įkėlimas baigtas - + To use the %s option - + Error Klaida diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index e661ad860..b83946131 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -2127,6 +2127,14 @@ Adrese: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2178,12 +2186,12 @@ Adrese: %4 Bitcoin versija - + Usage: Lietojums: - + Send command to -server or bitcoind Nosūtīt komantu uz -server vai bitcoind @@ -2193,17 +2201,17 @@ Adrese: %4 Komandu saraksts - + Get help for a command Palīdzība par komandu - + Options: Iespējas: - + Specify configuration file (default: bitcoin.conf) Norādiet konfigurācijas failu (pēc noklusēšanas: bitcoin.conf) @@ -2218,7 +2226,7 @@ Adrese: %4 Norādiet datu direktoriju - + Set database cache size in megabytes (default: 25) Uzstādiet datu bāzes bufera izmēru megabaitos (pēc noklusēšanas: 25) @@ -2233,12 +2241,12 @@ Adrese: %4 Uzturēt līdz <n> savienojumiem ar citiem mezgliem(pēc noklusēšanas: 125) - + Connect to a node to retrieve peer addresses, and disconnect Pievienoties mezglam, lai iegūtu citu mezglu adreses, un atvienoties - + Specify your own public address Norādiet savu publisko adresi @@ -2248,7 +2256,7 @@ Adrese: %4 Slieksnis pārkāpējmezglu atvienošanai (pēc noklusēšanas: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Sekundes, cik ilgi atturēt pārkāpējmezglus no atkārtotas pievienošanās (pēc noklusēšanas: 86400) @@ -2268,17 +2276,17 @@ Adrese: %4 Pieņemt komandrindas un JSON-RPC komandas - + Run in the background as a daemon and accept commands Darbināt fonā kā servisu un pieņemt komandas - + Use the test network Izmantot testa tīklu - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2422,11 +2430,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2513,7 +2516,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2528,7 +2531,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2538,17 +2541,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2557,6 +2560,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2632,6 +2645,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2643,7 +2661,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2683,32 +2716,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections JSON-RPC savienojumu parole - + Allow JSON-RPC connections from specified IP address Atļaut JSON-RPC savienojumus no norādītās IP adreses - + Send commands to node running on <ip> (default: 127.0.0.1) Nosūtīt komandas mezglam, kas darbojas adresē <ip> (pēc noklusēšanas: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Izpildīt komandu, kad labāk atbilstošais bloks izmainās (%s cmd aizvieto ar bloka hešu) - + Upgrade wallet to latest format Atjaunot maciņa formātu uz jaunāko - + Set key pool size to <n> (default: 100) Uzstādīt atslēgu bufera izmēru uz <n> (pēc noklusēšanas: 100) @@ -2718,12 +2751,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Atkārtoti skanēt bloku virkni, meklējot trūkstošās maciņa transakcijas - + Use OpenSSL (https) for JSON-RPC connections JSON-RPC savienojumiem izmantot OpenSSL (https) - + Server certificate file (default: server.cert) Servera sertifikāta fails (pēc noklusēšanas: server.cert) @@ -2733,22 +2766,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Servera privātā atslēga (pēc noklusēšanas: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Pieņemamie šifri (pēc noklusēšanas: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Šis palīdzības paziņojums - + Unable to bind to %s on this computer (bind returned error %d, %s) Nevar pievienoties pie %s šajā datorā (pievienošanās atgrieza kļūdu %d, %s) - + Connect through socks proxy Savienoties caurs socks proxy @@ -2758,12 +2791,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Atļaut DNS uzmeklēšanu priekš -addnode, -seednode un -connect - + Loading addresses... Ielādē adreses... - + Error loading wallet.dat: Wallet corrupted Nevar ielādēt wallet.dat: maciņš bojāts @@ -2773,22 +2806,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar ielādēt wallet.dat: maciņa atvēršanai nepieciešama jaunāka Bitcoin versija - + Wallet needed to be rewritten: restart Bitcoin to complete Bija nepieciešams pārstartēt maciņu: pabeigšanai pārstartējiet Bitcoin - + Error loading wallet.dat Kļūda ielādējot wallet.dat - + Invalid -proxy address: '%s' Nederīga -proxy adrese: '%s' - + Unknown network specified in -onlynet: '%s' -onlynet komandā norādīts nepazīstams tīkls: '%s' @@ -2798,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Pieprasīta nezināma -socks proxy versija: %i - + Cannot resolve -bind address: '%s' Nevar uzmeklēt -bind adresi: '%s' @@ -2808,7 +2841,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar atrisināt -externalip adresi: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Nederīgs daudzums priekš -paytxfree=<amount>: '%s' @@ -2818,17 +2851,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nederīgs daudzums - + Insufficient funds Nepietiek bitkoinu - + Loading block index... Ielādē bloku indeksu... - + Add a node to connect to and attempt to keep the connection open Pievienot mezglu, kam pievienoties un turēt savienojumu atvērtu @@ -2838,17 +2871,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar pievienoties %s uz šī datora. Bitcoin droši vien jau darbojas. - + Fee per KB to add to transactions you send Maksa par KB, ko pievienot nosūtāmajām transakcijām - + Loading wallet... Ielādē maciņu... - + Cannot downgrade wallet Nevar maciņa formātu padarīt vecāku @@ -2858,22 +2891,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nevar ierakstīt adresi pēc noklusēšanas - + Rescanning... Skanēju no jauna... - + Done loading Ielāde pabeigta - + To use the %s option Izmantot opciju %s - + Error Kļūda diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 2d949897e..47fffc835 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -2133,6 +2133,14 @@ Adresse: %4 til + + WalletModel + + + Send Coins + Send Bitcoins + + WalletView @@ -2184,12 +2192,12 @@ Adresse: %4 Bitcoin versjon - + Usage: Bruk: - + Send command to -server or bitcoind Send kommando til -server eller bitcoind @@ -2199,17 +2207,17 @@ Adresse: %4 List opp kommandoer - + Get help for a command Vis hjelpetekst for en kommando - + Options: Innstillinger: - + Specify configuration file (default: bitcoin.conf) Angi konfigurasjonsfil (standardverdi: bitcoin.conf) @@ -2224,7 +2232,7 @@ Adresse: %4 Angi mappe for datafiler - + Set database cache size in megabytes (default: 25) Sett størrelse på mellomlager for database i megabytes (standardverdi: 25) @@ -2239,12 +2247,12 @@ Adresse: %4 Hold maks <n> koblinger åpne til andre noder (standardverdi: 125) - + Connect to a node to retrieve peer addresses, and disconnect Koble til node for å hente adresser til andre noder, koble så fra igjen - + Specify your own public address Angi din egen offentlige adresse @@ -2254,7 +2262,7 @@ Adresse: %4 Grenseverdi for å koble fra noder med dårlig oppførsel (standardverdi: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Antall sekunder noder med dårlig oppførsel hindres fra å koble til på nytt (standardverdi: 86400) @@ -2274,17 +2282,17 @@ Adresse: %4 Ta imot kommandolinje- og JSON-RPC-kommandoer - + Run in the background as a daemon and accept commands Kjør i bakgrunnen som daemon og ta imot kommandoer - + Use the test network Bruk testnettverket - + Accept connections from outside (default: 1 if no -proxy or -connect) Ta imot tilkoblinger fra utsiden (standardverdi: 1 hvis uten -proxy eller -connect) @@ -2437,11 +2445,6 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Error: Disk space is low! - - - Error: Transaction creation failed! - Feil: Opprettelse av transaksjon feilet - Error: Wallet locked, unable to create transaction! @@ -2528,7 +2531,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ - + Not enough file descriptors available. @@ -2543,7 +2546,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ - + Verifying blocks... Verifiserer blokker... @@ -2553,17 +2556,17 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Verifiserer lommebok... - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2572,6 +2575,16 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Invalid -tor address: '%s' Ugyldig -tor adresse: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Shrink debug.log file on client startup (default: 1 when no -debug) Krymp debug.log filen når klienten starter (standardverdi: 1 hvis uten -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Bruk UPnP for lytteport (standardverdi: 0) @@ -2698,32 +2731,32 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ - + Password for JSON-RPC connections Passord for JSON-RPC forbindelser - + Allow JSON-RPC connections from specified IP address Tillat JSON-RPC tilkoblinger fra angitt IP-adresse - + Send commands to node running on <ip> (default: 127.0.0.1) Send kommandoer til node på <ip> (standardverdi: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Eksekvér kommando når beste blokk endrer seg (%s i kommandoen erstattes med blokkens hash) - + Upgrade wallet to latest format Oppgradér lommebok til nyeste format - + Set key pool size to <n> (default: 100) Angi størrelse på nøkkel-lager til <n> (standardverdi: 100) @@ -2733,12 +2766,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Se gjennom blokk-kjeden etter manglende lommeboktransaksjoner - + Use OpenSSL (https) for JSON-RPC connections Bruk OpenSSL (https) for JSON-RPC forbindelser - + Server certificate file (default: server.cert) Servers sertifikat (standardverdi: server.cert) @@ -2748,22 +2781,22 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Servers private nøkkel (standardverdi: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Akseptable krypteringsmetoder (standardverdi: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Denne hjelpemeldingen - + Unable to bind to %s on this computer (bind returned error %d, %s) Kan ikke binde til %s på denne datamaskinen (bind returnerte feil %d, %s) - + Connect through socks proxy Koble til gjennom socks proxy @@ -2773,12 +2806,12 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Tillat DNS oppslag for -addnode, -seednode og -connect - + Loading addresses... Laster adresser... - + Error loading wallet.dat: Wallet corrupted Feil ved lasting av wallet.dat: Lommeboken er skadet @@ -2788,22 +2821,22 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Feil ved lasting av wallet.dat: Lommeboken krever en nyere versjon av Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Lommeboken måtte skrives om: start Bitcoin på nytt for å fullføre - + Error loading wallet.dat Feil ved lasting av wallet.dat - + Invalid -proxy address: '%s' Ugyldig -proxy adresse: '%s' - + Unknown network specified in -onlynet: '%s' Ukjent nettverk angitt i -onlynet '%s' @@ -2813,7 +2846,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Ukjent -socks proxy versjon angitt: %i - + Cannot resolve -bind address: '%s' Kunne ikke slå opp -bind adresse: '%s' @@ -2823,7 +2856,7 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Kunne ikke slå opp -externalip adresse: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ugyldig beløp for -paytxfee=<beløp>: '%s' @@ -2833,17 +2866,17 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Ugyldig beløp - + Insufficient funds Utilstrekkelige midler - + Loading block index... Laster blokkindeks... - + Add a node to connect to and attempt to keep the connection open Legg til node for tilkobling og hold forbindelsen åpen @@ -2853,17 +2886,17 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Kan ikke binde til %s på denne datamaskinen. Sannsynligvis kjører Bitcoin allerede. - + Fee per KB to add to transactions you send Gebyr per KB for transaksjoner du sender - + Loading wallet... Laster lommebok... - + Cannot downgrade wallet Kan ikke nedgradere lommebok @@ -2873,22 +2906,22 @@ For eksempel: varselmelding=echo %%s | mail -s "Bitcoin varsel" admin@ Kan ikke skrive standardadresse - + Rescanning... Leser gjennom... - + Done loading Ferdig med lasting - + To use the %s option For å bruke %s opsjonen - + Error Feil diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 5926119cf..8a5850d31 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -2132,6 +2132,14 @@ Adres: %4 naar + + WalletModel + + + Send Coins + Verstuur munten + + WalletView @@ -2183,12 +2191,12 @@ Adres: %4 Bitcoinversie - + Usage: Gebruik: - + Send command to -server or bitcoind Stuur commando naar -server of bitcoind @@ -2198,17 +2206,17 @@ Adres: %4 Lijst van commando's - + Get help for a command Toon hulp voor een commando - + Options: Opties: - + Specify configuration file (default: bitcoin.conf) Specificeer configuratiebestand (standaard: bitcoin.conf) @@ -2225,7 +2233,7 @@ Adres: %4 Stel datamap in - + Set database cache size in megabytes (default: 25) Stel databankcachegrootte in in megabytes (standaard: 25) @@ -2240,12 +2248,12 @@ Adres: %4 Onderhoud maximaal <n> verbindingen naar peers (standaard: 125) - + Connect to a node to retrieve peer addresses, and disconnect Verbind naar een node om adressen van anderen op te halen, en verbreek vervolgens de verbinding - + Specify your own public address Specificeer uw eigen publieke adres @@ -2255,7 +2263,7 @@ Adres: %4 Drempel om verbinding te verbreken naar zich misdragende peers (standaard: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Aantal seconden dat zich misdragende peers niet opnieuw mogen verbinden (standaard: 86400) @@ -2275,17 +2283,17 @@ Adres: %4 Aanvaard commandoregel- en JSON-RPC-commando's - + Run in the background as a daemon and accept commands Draai in de achtergrond als daemon en aanvaard commando's - + Use the test network Gebruik het testnetwerk - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepteer verbindingen van buitenaf (standaard: 1 als geen -proxy of -connect is opgegeven) @@ -2437,11 +2445,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Fout: Weinig vrije diskruimte! - - - Error: Transaction creation failed! - Fout: Aanmaak transactie mislukt! - Error: Wallet locked, unable to create transaction! @@ -2528,7 +2531,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Hoe grondig de blokverificatie is (0-4, standaard: 3) - + Not enough file descriptors available. Niet genoeg file descriptors beschikbaar. @@ -2543,7 +2546,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Stel het aantal threads in om RPC-aanvragen mee te bedienen (standaard: 4) - + Verifying blocks... Blokken aan het controleren... @@ -2553,17 +2556,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Portomonnee aan het controleren... - + Imports blocks from external blk000??.dat file Importeert blokken van extern blk000??.dat bestand - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Stel het aantal threads voor scriptverificatie in (max 16, 0 = auto, <0 = laat zoveel cores vrij, standaard: 0) - + Information Informatie @@ -2572,6 +2575,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Ongeldig -tor adres: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Verklein debug.log-bestand bij het opstarten van de client (standaard: 1 als geen -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Systeemfout: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Gebruik UPnP om de luisterende poort te mappen (standaard: 0) @@ -2698,32 +2731,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat corrupt, veiligstellen mislukt - + Password for JSON-RPC connections Wachtwoord voor JSON-RPC-verbindingen - + Allow JSON-RPC connections from specified IP address Sta JSON-RPC verbindingen van opgegeven IP-adres toe - + Send commands to node running on <ip> (default: 127.0.0.1) Verstuur commando's naar proces dat op <ip> draait (standaard: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Voer commando uit zodra het beste blok verandert (%s in cmd wordt vervangen door blockhash) - + Upgrade wallet to latest format Vernieuw portemonnee naar nieuwste versie - + Set key pool size to <n> (default: 100) Stel sleutelpoelgrootte in op <n> (standaard: 100) @@ -2733,12 +2766,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Doorzoek de blokketen op ontbrekende portemonnee-transacties - + Use OpenSSL (https) for JSON-RPC connections Gebruik OpenSSL (https) voor JSON-RPC-verbindingen - + Server certificate file (default: server.cert) Certificaat-bestand voor server (standaard: server.cert) @@ -2748,22 +2781,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Geheime sleutel voor server (standaard: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Aanvaardbare ciphers (standaard: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Dit helpbericht - + Unable to bind to %s on this computer (bind returned error %d, %s) Niet in staat om aan %s te binden op deze computer (bind gaf error %d, %s) - + Connect through socks proxy Verbind via een socks-proxy @@ -2773,12 +2806,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Sta DNS-naslag toe voor -addnode, -seednode en -connect - + Loading addresses... Adressen aan het laden... - + Error loading wallet.dat: Wallet corrupted Fout bij laden wallet.dat: Portemonnee corrupt @@ -2788,22 +2821,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Fout bij laden wallet.dat: Portemonnee vereist een nieuwere versie van Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Portemonnee moest herschreven worden: Herstart Bitcoin om te voltooien - + Error loading wallet.dat Fout bij laden wallet.dat - + Invalid -proxy address: '%s' Ongeldig -proxy adres: '%s' - + Unknown network specified in -onlynet: '%s' Onbekend netwerk gespecificeerd in -onlynet: '%s' @@ -2813,7 +2846,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Onbekende -socks proxyversie aangegeven: %i - + Cannot resolve -bind address: '%s' Kan -bind adres niet herleiden: '%s' @@ -2823,7 +2856,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Kan -externlip adres niet herleiden: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ongeldig bedrag voor -paytxfee=<bedrag>: '%s' @@ -2833,17 +2866,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ongeldig bedrag - + Insufficient funds Ontoereikend saldo - + Loading block index... Blokindex aan het laden... - + Add a node to connect to and attempt to keep the connection open Voeg een node om naar te verbinden toe en probeer de verbinding open te houden @@ -2853,17 +2886,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Niet in staat om aan %s te binden op deze computer. Bitcoin draait vermoedelijk reeds. - + Fee per KB to add to transactions you send Kosten per KB om aan transacties toe te voegen die u verstuurt - + Loading wallet... Portemonnee aan het laden... - + Cannot downgrade wallet Kan portemonnee niet downgraden @@ -2873,22 +2906,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Kan standaardadres niet schrijven - + Rescanning... Blokketen aan het doorzoeken... - + Done loading Klaar met laden - + To use the %s option Om de %s optie te gebruiken - + Error Fout diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 2b239c035..2738b2e81 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -2132,6 +2132,14 @@ Adres: %4 do + + WalletModel + + + Send Coins + Wyślij płatność + + WalletView @@ -2183,12 +2191,12 @@ Adres: %4 Wersja Bitcoin - + Usage: Użycie: - + Send command to -server or bitcoind Wyślij polecenie do -server lub bitcoind @@ -2198,17 +2206,17 @@ Adres: %4 Lista poleceń - + Get help for a command Uzyskaj pomoc do polecenia - + Options: Opcje: - + Specify configuration file (default: bitcoin.conf) Wskaż plik konfiguracyjny (domyślnie: bitcoin.conf) @@ -2223,7 +2231,7 @@ Adres: %4 Wskaż folder danych - + Set database cache size in megabytes (default: 25) Ustaw rozmiar w megabajtach cache-u bazy danych (domyślnie: 25) @@ -2238,12 +2246,12 @@ Adres: %4 Utrzymuj maksymalnie <n> połączeń z peerami (domyślnie: 125) - + Connect to a node to retrieve peer addresses, and disconnect Podłącz się do węzła aby otrzymać adresy peerów i rozłącz - + Specify your own public address Podaj swój publiczny adres @@ -2253,7 +2261,7 @@ Adres: %4 Próg po którym nastąpi rozłączenie nietrzymających się zasad peerów (domyślnie: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Czas w sekundach, przez jaki nietrzymający się zasad peerzy nie będą mogli ponownie się podłączyć (domyślnie: 86400) @@ -2273,17 +2281,17 @@ Adres: %4 Akceptuj linię poleceń oraz polecenia JSON-RPC - + Run in the background as a daemon and accept commands Uruchom w tle jako daemon i przyjmuj polecenia - + Use the test network Użyj sieci testowej - + Accept connections from outside (default: 1 if no -proxy or -connect) Akceptuj połączenia z zewnątrz (domyślnie: 1 jeśli nie ustawiono -proxy lub -connect) @@ -2436,11 +2444,6 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Error: Disk space is low! Błąd: Mało miejsca na dysku! - - - Error: Transaction creation failed! - Błąd: Utworzenie transakcji nie powiodło się! - Error: Wallet locked, unable to create transaction! @@ -2527,7 +2530,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Jak dokładna jest weryfikacja bloku (0-4, domyślnie: 3) - + Not enough file descriptors available. @@ -2542,7 +2545,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Ustaw liczbę wątków do odwołań RPC (domyślnie: 4) - + Verifying blocks... Weryfikacja bloków... @@ -2552,17 +2555,17 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Weryfikacja portfela... - + Imports blocks from external blk000??.dat file Importuj bloki z zewnętrznego pliku blk000??.dat - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Ustaw liczbę wątków skryptu weryfikacji (do 16, 0 = auto, <0 = zostawia taką ilość rdzenie wolnych, domyślnie: 0) - + Information Informacja @@ -2571,6 +2574,16 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Invalid -tor address: '%s' Nieprawidłowy adres -tor: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2646,6 +2659,11 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Shrink debug.log file on client startup (default: 1 when no -debug) Zmniejsz plik debug.log przy starcie programu (domyślnie: 1 jeśli nie użyto -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2657,7 +2675,22 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Błąd systemu: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Używaj UPnP do mapowania portu nasłuchu (domyślnie: 0) @@ -2697,32 +2730,32 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo wallet.dat uszkodzony, odtworzenie się nie powiodło - + Password for JSON-RPC connections Hasło do połączeń JSON-RPC - + Allow JSON-RPC connections from specified IP address Przyjmuj połączenia JSON-RPC ze wskazanego adresu IP - + Send commands to node running on <ip> (default: 127.0.0.1) Wysyłaj polecenia do węzła działającego na <ip> (domyślnie: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Wykonaj polecenie kiedy najlepszy blok ulegnie zmianie (%s w komendzie zastanie zastąpione przez hash bloku) - + Upgrade wallet to latest format Zaktualizuj portfel do najnowszego formatu. - + Set key pool size to <n> (default: 100) Ustaw rozmiar puli kluczy na <n> (domyślnie: 100) @@ -2732,12 +2765,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Przeskanuj blok łańcuchów żeby znaleźć zaginione transakcje portfela - + Use OpenSSL (https) for JSON-RPC connections Użyj OpenSSL (https) do połączeń JSON-RPC - + Server certificate file (default: server.cert) Plik certyfikatu serwera (domyślnie: server.cert) @@ -2747,22 +2780,22 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Klucz prywatny serwera (domyślnie: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Aceptowalne szyfry (domyślnie: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ta wiadomość pomocy - + Unable to bind to %s on this computer (bind returned error %d, %s) Nie można przywiązać %s na tym komputerze (bind returned error %d, %s) - + Connect through socks proxy Łączy przez proxy socks @@ -2772,12 +2805,12 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Zezwól -addnode, -seednode i -connect na łączenie się z serwerem DNS - + Loading addresses... Wczytywanie adresów... - + Error loading wallet.dat: Wallet corrupted Błąd ładowania wallet.dat: Uszkodzony portfel @@ -2787,22 +2820,22 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Błąd ładowania wallet.dat: Portfel wymaga nowszej wersji Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Portfel wymaga przepisania: zrestartuj Bitcoina żeby ukończyć - + Error loading wallet.dat Błąd ładowania wallet.dat - + Invalid -proxy address: '%s' Nieprawidłowy adres -proxy: '%s' - + Unknown network specified in -onlynet: '%s' Nieznana sieć w -onlynet: '%s' @@ -2812,7 +2845,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nieznana wersja proxy w -socks: %i - + Cannot resolve -bind address: '%s' Nie można uzyskać adresu -bind: '%s' @@ -2822,7 +2855,7 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nie można uzyskać adresu -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Nieprawidłowa kwota dla -paytxfee=<amount>: '%s' @@ -2832,17 +2865,17 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nieprawidłowa kwota - + Insufficient funds Niewystarczające środki - + Loading block index... Ładowanie indeksu bloku... - + Add a node to connect to and attempt to keep the connection open Dodaj węzeł do łączenia się and attempt to keep the connection open @@ -2852,18 +2885,18 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nie można przywiązać %s na tym komputerze. Bitcoin prawdopodobnie już działa. - + Fee per KB to add to transactions you send - + Loading wallet... Wczytywanie portfela... - + Cannot downgrade wallet Nie można dezaktualizować portfela @@ -2873,22 +2906,22 @@ na przykład: alertnotify=echo %%s | mail -s "Alarm Bitcoin" admin@foo Nie można zapisać domyślnego adresu - + Rescanning... Ponowne skanowanie... - + Done loading Wczytywanie zakończone - + To use the %s option Aby użyć opcji %s - + Error Błąd diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 80681e8ca..fbf536e73 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -2131,6 +2131,14 @@ Endereço: %4 para + + WalletModel + + + Send Coins + Send Coins + + WalletView @@ -2182,12 +2190,12 @@ Endereço: %4 Versão do Bitcoin - + Usage: Uso: - + Send command to -server or bitcoind Enviar comando para -server ou bitcoind @@ -2197,17 +2205,17 @@ Endereço: %4 Lista de comandos - + Get help for a command Obtenha ajuda sobre um comando - + Options: Opções: - + Specify configuration file (default: bitcoin.conf) Especifique um arquivo de configurações (padrão: bitcoin.conf) @@ -2222,7 +2230,7 @@ Endereço: %4 Especificar diretório de dados - + Set database cache size in megabytes (default: 25) Definir o tamanho do cache do banco de dados em megabytes (padrão: 25) @@ -2237,12 +2245,12 @@ Endereço: %4 Manter no máximo <n> conexões aos peers (padrão: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conectar a um nó para receber endereços de participantes, e desconectar. - + Specify your own public address Especificar seu próprio endereço público @@ -2252,7 +2260,7 @@ Endereço: %4 Limite para desconectar peers mal comportados (padrão: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Número de segundos para impedir que peers mal comportados reconectem (padrão: 86400) @@ -2272,17 +2280,17 @@ Endereço: %4 Aceitar linha de comando e comandos JSON-RPC - + Run in the background as a daemon and accept commands Rodar em segundo plano como serviço e aceitar comandos - + Use the test network Usar rede de teste - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceitar conexões externas (padrão: 1 se opções -proxy ou -connect não estiverem presentes) @@ -2436,11 +2444,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Erro: Espaço em disco insuficiente! - - - Error: Transaction creation failed! - Erro: Criação da transação falhou! - Error: Wallet locked, unable to create transaction! @@ -2527,7 +2530,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Quão minuciosa é a verificação dos blocos (0-4, padrão: 3) - + Not enough file descriptors available. @@ -2542,7 +2545,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Defina o número de threads de script de verificação. (Padrão: 4) - + Verifying blocks... Verificando blocos... @@ -2552,17 +2555,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Verificando carteira... - + Imports blocks from external blk000??.dat file Importar blocos de um arquivo externo blk000??.dat - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Informação @@ -2571,6 +2574,16 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Endereço -tor inválido: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2646,6 +2659,11 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Encolher arquivo debug.log ao iniciar o cliente (padrão 1 se opção -debug não estiver presente) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2657,7 +2675,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Erro de sistema: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Usar UPnP para mapear porta de escuta (padrão: 0) @@ -2697,32 +2730,32 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat corrompido, recuperação falhou - + Password for JSON-RPC connections Senha para conexões JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitir conexões JSON-RPC de endereços IP específicos - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comando para nó rodando em <ip> (pardão: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Executar comando quando o melhor bloco mudar (%s no comando será substituído pelo hash do bloco) - + Upgrade wallet to latest format Atualizar carteira para o formato mais recente - + Set key pool size to <n> (default: 100) Determinar tamanho do pool de endereços para <n> (padrão: 100) @@ -2732,12 +2765,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Re-escanear blocos procurando por transações perdidas da carteira - + Use OpenSSL (https) for JSON-RPC connections Usar OpenSSL (https) para conexões JSON-RPC - + Server certificate file (default: server.cert) Arquivo de certificado do servidor (padrão: server.cert) @@ -2747,22 +2780,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chave privada do servidor (padrão: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Algoritmos de criptografia aceitos (padrão: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Esta mensagem de ajuda - + Unable to bind to %s on this computer (bind returned error %d, %s) Impossível vincular a %s neste computador (bind retornou erro %d, %s) - + Connect through socks proxy Conectar através de um proxy socks @@ -2772,12 +2805,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Permitir consultas DNS para -addnode, -seednode e -connect - + Loading addresses... Carregando endereços... - + Error loading wallet.dat: Wallet corrupted Erro ao carregar wallet.dat: Carteira corrompida @@ -2787,22 +2820,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Erro ao carregar wallet.dat: Carteira requer uma versão mais nova do Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete A Carteira precisou ser reescrita: reinicie o Bitcoin para completar - + Error loading wallet.dat Erro ao carregar wallet.dat - + Invalid -proxy address: '%s' Endereço -proxy inválido: '%s' - + Unknown network specified in -onlynet: '%s' Rede desconhecida especificada em -onlynet: '%s' @@ -2812,7 +2845,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Versão desconhecida do proxy -socks requisitada: %i - + Cannot resolve -bind address: '%s' Impossível encontrar o endereço -bind: '%s' @@ -2822,7 +2855,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossível encontrar endereço -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantidade inválida para -paytxfee=<quantidade>: '%s' @@ -2832,17 +2865,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Quantidade inválida - + Insufficient funds Saldo insuficiente - + Loading block index... Carregando índice de blocos... - + Add a node to connect to and attempt to keep the connection open Adicionar um nó com o qual se conectar e tentar manter a conexão ativa @@ -2852,17 +2885,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Impossível vincular a %s neste computador. O Bitcoin provavelmente já está rodando. - + Fee per KB to add to transactions you send Taxa por KB a ser acrescida nas transações que você enviar - + Loading wallet... Carregando carteira... - + Cannot downgrade wallet Não é possível fazer downgrade da carteira @@ -2872,22 +2905,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Não foi possível escrever no endereço padrão - + Rescanning... Re-escaneando... - + Done loading Carregamento terminado - + To use the %s option Para usar a opção %s - + Error Erro diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index c387ff9ab..0aed1f429 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -2132,6 +2132,14 @@ Endereço: %4 até + + WalletModel + + + Send Coins + Enviar Moedas + + WalletView @@ -2183,12 +2191,12 @@ Endereço: %4 Versão Bitcoin - + Usage: Utilização: - + Send command to -server or bitcoind Enviar comando para -server ou bitcoind @@ -2198,17 +2206,17 @@ Endereço: %4 Listar comandos - + Get help for a command Obter ajuda para um comando - + Options: Opções: - + Specify configuration file (default: bitcoin.conf) Especificar ficheiro de configuração (por defeito: bitcoin.conf) @@ -2223,7 +2231,7 @@ Endereço: %4 Especificar pasta de dados - + Set database cache size in megabytes (default: 25) Definir o tamanho da cache de base de dados em megabytes (por defeito: 25) @@ -2238,12 +2246,12 @@ Endereço: %4 Manter no máximo <n> ligações a outros nós da rede (por defeito: 125) - + Connect to a node to retrieve peer addresses, and disconnect Ligar a um nó para recuperar endereços de pares, e desligar - + Specify your own public address Especifique o seu endereço público @@ -2253,7 +2261,7 @@ Endereço: %4 Tolerância para desligar nós mal-formados (por defeito: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Número de segundos a impedir que nós mal-formados se liguem de novo (por defeito: 86400) @@ -2273,17 +2281,17 @@ Endereço: %4 Aceitar comandos da consola e JSON-RPC - + Run in the background as a daemon and accept commands Correr o processo como um daemon e aceitar comandos - + Use the test network Utilizar a rede de testes - testnet - + Accept connections from outside (default: 1 if no -proxy or -connect) Aceitar ligações externas (padrão: 1 sem -proxy ou -connect) @@ -2437,11 +2445,6 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Error: Disk space is low! Erro: Pouco espaço em disco! - - - Error: Transaction creation failed! - Erro: A criação da transacção falhou! - Error: Wallet locked, unable to create transaction! @@ -2528,7 +2531,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Qual a minúcia na verificação de blocos (0-4, por defeito: 3) - + Not enough file descriptors available. Descritores de ficheiros disponíveis são insuficientes. @@ -2543,7 +2546,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Defina o número de processos para servir as chamadas RPC (por defeito: 4) - + Verifying blocks... Verificando blocos... @@ -2553,17 +2556,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Verificando a carteira... - + Imports blocks from external blk000??.dat file Importar blocos de um ficheiro blk000??.dat externo - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Defina o número de processos de verificação (até 16, 0 = automático, <0 = disponibiliza esse número de núcleos livres, por defeito: 0) - + Information Informação @@ -2572,6 +2575,16 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Invalid -tor address: '%s' Endereço -tor inválido: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Shrink debug.log file on client startup (default: 1 when no -debug) Encolher ficheiro debug.log ao iniciar o cliente (por defeito: 1 sem -debug definido) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Erro de sistema: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Usar UPnP para mapear a porta de escuta (padrão: 0) @@ -2698,32 +2731,32 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo wallet.dat corrupta, recuperação falhou - + Password for JSON-RPC connections Palavra-passe para ligações JSON-RPC - + Allow JSON-RPC connections from specified IP address Permitir ligações JSON-RPC do endereço IP especificado - + Send commands to node running on <ip> (default: 127.0.0.1) Enviar comandos para o nó a correr em <ip> (por defeito: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Executar comando quando mudar o melhor bloco (no comando, %s é substituído pela hash do bloco) - + Upgrade wallet to latest format Atualize a carteira para o formato mais recente - + Set key pool size to <n> (default: 100) Definir o tamanho da memória de chaves para <n> (por defeito: 100) @@ -2733,12 +2766,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Reexaminar a cadeia de blocos para transações em falta na carteira - + Use OpenSSL (https) for JSON-RPC connections Usar OpenSSL (https) para ligações JSON-RPC - + Server certificate file (default: server.cert) Ficheiro de certificado do servidor (por defeito: server.cert) @@ -2748,22 +2781,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Chave privada do servidor (por defeito: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Cifras aceitáveis (por defeito: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Esta mensagem de ajuda - + Unable to bind to %s on this computer (bind returned error %d, %s) Incapaz de vincular a %s neste computador (vínculo retornou erro %d, %s) - + Connect through socks proxy Ligar através de um proxy socks @@ -2773,12 +2806,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Permitir procuras DNS para -addnode, -seednode e -connect - + Loading addresses... Carregar endereços... - + Error loading wallet.dat: Wallet corrupted Erro ao carregar wallet.dat: Carteira danificada @@ -2788,22 +2821,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Erro ao carregar wallet.dat: A Carteira requer uma versão mais recente do Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete A Carteira precisou ser reescrita: reinicie o Bitcoin para completar - + Error loading wallet.dat Erro ao carregar wallet.dat - + Invalid -proxy address: '%s' Endereço -proxy inválido: '%s' - + Unknown network specified in -onlynet: '%s' Rede desconhecida especificada em -onlynet: '%s' @@ -2813,7 +2846,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Versão desconhecida de proxy -socks requisitada: %i - + Cannot resolve -bind address: '%s' Não conseguiu resolver endereço -bind: '%s' @@ -2823,7 +2856,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Não conseguiu resolver endereço -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Quantia inválida para -paytxfee=<amount>: '%s' @@ -2833,17 +2866,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Quantia inválida - + Insufficient funds Fundos insuficientes - + Loading block index... Carregar índice de blocos... - + Add a node to connect to and attempt to keep the connection open Adicione um nó ao qual se ligar e tentar manter a ligação aberta @@ -2853,17 +2886,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Incapaz de vincular à porta %s neste computador. Provavelmente o Bitcoin já está a funcionar. - + Fee per KB to add to transactions you send Taxa por KB a adicionar a transações enviadas - + Loading wallet... Carregar carteira... - + Cannot downgrade wallet Impossível mudar a carteira para uma versão anterior @@ -2873,22 +2906,22 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Impossível escrever endereço por defeito - + Rescanning... Reexaminando... - + Done loading Carregamento completo - + To use the %s option Para usar a opção %s - + Error Erro diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index db011784d..ee633e26f 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -2123,6 +2123,14 @@ Address: %4 către + + WalletModel + + + Send Coins + Trimite Bitcoin + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 versiunea Bitcoin - + Usage: Uz: - + Send command to -server or bitcoind Trimite comanda la -server sau bitcoind @@ -2189,17 +2197,17 @@ Address: %4 Listă de comenzi - + Get help for a command Ajutor pentru o comandă - + Options: Setări: - + Specify configuration file (default: bitcoin.conf) Specifica-ți configurația fisierului (in mod normal: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 Specifica datele directorului - + Set database cache size in megabytes (default: 25) Seteaza marimea cache a bazei de date in MB (initial: 25) @@ -2229,12 +2237,12 @@ Address: %4 Se menține la cele mai multe conexiuni <n> cu colegii (implicit: 125) - + Connect to a node to retrieve peer addresses, and disconnect Conecteaza-te la nod pentru a optine adresa peer, si deconecteaza-te - + Specify your own public address Specifica adresa ta publica @@ -2244,7 +2252,7 @@ Address: %4 Prag pentru deconectarea colegii funcționează corect (implicit: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Numărul de secunde pentru a păstra colegii funcționează corect la reconectare (implicit: 86400) @@ -2264,17 +2272,17 @@ Address: %4 Se accepta command line si comenzi JSON-RPC - + Run in the background as a daemon and accept commands Ruleaza în background ca un demon și accepta comenzi. - + Use the test network Utilizeaza test de retea - + Accept connections from outside (default: 1 if no -proxy or -connect) Accepta conexiuni de la straini (initial: 1 if no -proxy or -connect) @@ -2419,11 +2427,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2510,7 +2513,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2525,7 +2528,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2535,17 +2538,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2554,6 +2557,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2629,6 +2642,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2640,7 +2658,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Foloseste UPnP pentru a vedea porturile (initial: 0) @@ -2680,32 +2713,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Parola pentru conectiunile JSON-RPC - + Allow JSON-RPC connections from specified IP address Permiteti conectiunile JSON-RPC de la o adresa IP specifica. - + Send commands to node running on <ip> (default: 127.0.0.1) Trimite comenzi la nod, ruland pe ip-ul (initial: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Executa comanda cand cel mai bun block se schimba (%s in cmd se inlocuieste cu block hash) - + Upgrade wallet to latest format Actualizeaza portofelul la ultimul format - + Set key pool size to <n> (default: 100) Setarea marimii cheii bezinului la <n>(initial 100) @@ -2715,12 +2748,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescanare lanțul de bloc pentru tranzacțiile portofel lipsă - + Use OpenSSL (https) for JSON-RPC connections Foloseste Open SSL(https) pentru coneciunile JSON-RPC - + Server certificate file (default: server.cert) Certificatul serverulu (initial: server.cert) @@ -2730,24 +2763,24 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cheia privata a serverului ( initial: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Accepta cifruri (initial: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Acest mesaj de ajutor. - + Unable to bind to %s on this computer (bind returned error %d, %s) Nu se poate lega %s cu acest calculator (retunare eroare legatura %d, %s) - + Connect through socks proxy Conectează prin proxy SOCKS @@ -2757,12 +2790,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Permite DNS-ului sa se uite dupa -addnode, -seednode si -connect - + Loading addresses... Încarc adrese... - + Error loading wallet.dat: Wallet corrupted Eroare incarcand wallet.dat: Portofel corupt @@ -2772,22 +2805,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Eroare incarcare wallet.dat: Portofelul are nevoie de o versiune Bitcoin mai noua - + Wallet needed to be rewritten: restart Bitcoin to complete Portofelul trebuie rescris: restarteaza aplicatia bitcoin pentru a face asta. - + Error loading wallet.dat Eroare incarcand wallet.dat - + Invalid -proxy address: '%s' Adresa proxy invalida: '%s' - + Unknown network specified in -onlynet: '%s' Retea specificata necunoscuta -onlynet: '%s' @@ -2797,7 +2830,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Necunoscut -socks proxy version requested: %i - + Cannot resolve -bind address: '%s' Nu se poate rezolca -bind address: '%s' @@ -2807,7 +2840,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Nu se poate rezolva -externalip address: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Suma invalida pentru -paytxfee=<amount>: '%s' @@ -2817,17 +2850,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Suma invalida - + Insufficient funds Fonduri insuficiente - + Loading block index... Încarc indice bloc... - + Add a node to connect to and attempt to keep the connection open Add a node to connect to and attempt to keep the connection open details suggestions history @@ -2839,17 +2872,17 @@ details suggestions history Imposibilitatea de a lega la% s pe acest computer. Bitcoin este, probabil, deja în execuție. - + Fee per KB to add to transactions you send Taxa pe kb pentru a adauga tranzactii trimise - + Loading wallet... Încarc portofel... - + Cannot downgrade wallet Nu se poate face downgrade la portofel @@ -2859,22 +2892,22 @@ details suggestions history Nu se poate scrie adresa initiala - + Rescanning... Rescanez... - + Done loading Încărcare terminată - + To use the %s option Pentru a folosii optiunea %s - + Error Eroare diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index 4a62472bf..5660bce01 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -810,7 +810,7 @@ Address: %4 Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Необязательная комиссия за каждый КБ транзакции, которая ускоряет обработку Ваших транзакций. Большинство транзакций занимают 1КБ. @@ -2132,12 +2132,20 @@ Address: %4 до + + WalletModel + + + Send Coins + Отправка + + WalletView &Export - + &Экспорт @@ -2183,12 +2191,12 @@ Address: %4 Версия - + Usage: Использование: - + Send command to -server or bitcoind Отправить команду на -server или bitcoind @@ -2199,17 +2207,17 @@ Address: %4 - + Get help for a command Получить помощь по команде - + Options: Опции: - + Specify configuration file (default: bitcoin.conf) Указать конфигурационный файл (по умолчанию: bitcoin.conf) @@ -2224,7 +2232,7 @@ Address: %4 Задать каталог данных - + Set database cache size in megabytes (default: 25) Установить размер кэша базы данных в мегабайтах (по умолчанию: 25) @@ -2239,12 +2247,12 @@ Address: %4 Поддерживать не более <n> подключений к узлам (по умолчанию: 125) - + Connect to a node to retrieve peer addresses, and disconnect Подключиться к узлу, чтобы получить список адресов других участников и отключиться - + Specify your own public address Укажите ваш собственный публичный адрес @@ -2254,7 +2262,7 @@ Address: %4 Порог для отключения неправильно ведущих себя узлов (по умолчанию: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Число секунд блокирования неправильно ведущих себя узлов (по умолчанию: 86400) @@ -2274,17 +2282,17 @@ Address: %4 Принимать командную строку и команды JSON-RPC - + Run in the background as a daemon and accept commands Запускаться в фоне как демон и принимать команды - + Use the test network Использовать тестовую сеть - + Accept connections from outside (default: 1 if no -proxy or -connect) Принимать подключения извне (по умолчанию: 1, если не используется -proxy или -connect) @@ -2438,11 +2446,6 @@ rpcpassword=%s Error: Disk space is low! Ошибка: мало места на диске! - - - Error: Transaction creation failed! - Ошибка: не удалось создать транзакцию! - Error: Wallet locked, unable to create transaction! @@ -2516,7 +2519,7 @@ rpcpassword=%s Generate coins (default: 0) - + Включить добычу монет (по умолчанию: 0) @@ -2529,9 +2532,9 @@ rpcpassword=%s Насколько тщательно проверять блок (0-4, по умолчанию: 3) - + Not enough file descriptors available. - + Недостаточно файловых дескрипторов. @@ -2544,7 +2547,7 @@ rpcpassword=%s Задать число потоков выполнения(по умолчанию: 4) - + Verifying blocks... Проверка блоков... @@ -2554,17 +2557,17 @@ rpcpassword=%s Проверка бумажника... - + Imports blocks from external blk000??.dat file Импортировать блоки из внешнего файла blk000??.dat - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Задать число потоков проверки скрипта (вплоть до 16, 0=авто, <0 = оставить столько ядер свободными, по умолчанию: 0) - + Information Информация @@ -2573,6 +2576,16 @@ rpcpassword=%s Invalid -tor address: '%s' Неверный адрес -tor: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Неверное количество в параметре -minrelaytxfee=<кол-во>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Неверное количество в параметре -mintxfee=<кол-во>: '%s' + Maintain a full transaction index (default: 0) @@ -2649,6 +2662,11 @@ rpcpassword=%s Shrink debug.log file on client startup (default: 1 when no -debug) Сжимать файл debug.log при запуске клиента (по умолчанию: 1, если нет -debug) + + + Signing transaction failed + Не удалось подписать транзакцию + Specify connection timeout in milliseconds (default: 5000) @@ -2660,7 +2678,22 @@ rpcpassword=%s Системная ошибка: - + + Transaction amount too small + Объём транзакции слишком мал + + + + Transaction amounts must be positive + Объём транзакции должен быть положителен + + + + Transaction too large + Транзакция слишком большая + + + Use UPnP to map the listening port (default: 0) Использовать UPnP для проброса порта (по умолчанию: 0) @@ -2700,32 +2733,32 @@ rpcpassword=%s wallet.dat повреждён, спасение данных не удалось - + Password for JSON-RPC connections Пароль для подключений JSON-RPC - + Allow JSON-RPC connections from specified IP address Разрешить подключения JSON-RPC с указанного IP - + Send commands to node running on <ip> (default: 127.0.0.1) Посылать команды узлу, запущенному на <ip> (по умолчанию: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Выполнить команду, когда появляется новый блок (%s в команде заменяется на хэш блока) - + Upgrade wallet to latest format Обновить бумажник до последнего формата - + Set key pool size to <n> (default: 100) Установить размер запаса ключей в <n> (по умолчанию: 100) @@ -2735,12 +2768,12 @@ rpcpassword=%s Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций - + Use OpenSSL (https) for JSON-RPC connections Использовать OpenSSL (https) для подключений JSON-RPC - + Server certificate file (default: server.cert) Файл серверного сертификата (по умолчанию: server.cert) @@ -2750,22 +2783,22 @@ rpcpassword=%s Приватный ключ сервера (по умолчанию: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Разрешённые алгоритмы (по умолчанию: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Эта справка - + Unable to bind to %s on this computer (bind returned error %d, %s) Невозможно привязаться к %s на этом компьютере (bind вернул ошибку %d, %s) - + Connect through socks proxy Подключаться через socks прокси @@ -2775,12 +2808,12 @@ rpcpassword=%s Разрешить поиск в DNS для -addnode, -seednode и -connect - + Loading addresses... Загрузка адресов... - + Error loading wallet.dat: Wallet corrupted Ошибка загрузки wallet.dat: Бумажник поврежден @@ -2790,22 +2823,22 @@ rpcpassword=%s Ошибка загрузки wallet.dat: бумажник требует более новую версию Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Необходимо перезаписать бумажник, перезапустите Bitcoin для завершения операции. - + Error loading wallet.dat Ошибка при загрузке wallet.dat - + Invalid -proxy address: '%s' Неверный адрес -proxy: '%s' - + Unknown network specified in -onlynet: '%s' В параметре -onlynet указана неизвестная сеть: '%s' @@ -2815,7 +2848,7 @@ rpcpassword=%s В параметре -socks запрошена неизвестная версия: %i - + Cannot resolve -bind address: '%s' Не удаётся разрешить адрес в параметре -bind: '%s' @@ -2825,7 +2858,7 @@ rpcpassword=%s Не удаётся разрешить адрес в параметре -externalip: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Неверное количество в параметре -paytxfee=<кол-во>: '%s' @@ -2835,17 +2868,17 @@ rpcpassword=%s Неверное количество - + Insufficient funds Недостаточно монет - + Loading block index... Загрузка индекса блоков... - + Add a node to connect to and attempt to keep the connection open Добавить узел для подключения и пытаться поддерживать соединение открытым @@ -2855,17 +2888,17 @@ rpcpassword=%s Невозможно привязаться к %s на этом компьютере. Возможно, Bitcoin уже работает. - + Fee per KB to add to transactions you send Комиссия на килобайт, добавляемая к вашим транзакциям - + Loading wallet... Загрузка бумажника... - + Cannot downgrade wallet Не удаётся понизить версию бумажника @@ -2875,22 +2908,22 @@ rpcpassword=%s Не удаётся записать адрес по умолчанию - + Rescanning... Сканирование... - + Done loading Загрузка завершена - + To use the %s option Чтобы использовать опцию %s - + Error Ошибка diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index e1c1c051c..cebdff0e0 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -2126,6 +2126,14 @@ Adresa: %4 do + + WalletModel + + + Send Coins + Poslať Bitcoins + + WalletView @@ -2177,12 +2185,12 @@ Adresa: %4 Bitcoin verzia - + Usage: Použitie: - + Send command to -server or bitcoind Odoslať príkaz -server alebo bitcoind @@ -2192,17 +2200,17 @@ Adresa: %4 Zoznam príkazov - + Get help for a command Dostať pomoc pre príkaz - + Options: Možnosti: - + Specify configuration file (default: bitcoin.conf) Určiť súbor s nastaveniami (predvolené: bitcoin.conf) @@ -2217,7 +2225,7 @@ Adresa: %4 Určiť priečinok s dátami - + Set database cache size in megabytes (default: 25) @@ -2232,12 +2240,12 @@ Adresa: %4 Udržiavať maximálne <n> spojení (predvolené: 125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2247,7 +2255,7 @@ Adresa: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2267,17 +2275,17 @@ Adresa: %4 Prijímať príkazy z príkazového riadku a JSON-RPC - + Run in the background as a daemon and accept commands Bežať na pozadí ako démon a prijímať príkazy - + Use the test network Použiť testovaciu sieť - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2421,11 +2429,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2512,7 +2515,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2527,7 +2530,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2537,17 +2540,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2556,6 +2559,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Neplatná adresa tor: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2631,6 +2644,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2642,7 +2660,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Skúsiť použiť UPnP pre mapovanie počúvajúceho portu (default: 0) @@ -2682,32 +2715,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Heslo pre JSON-rPC spojenia - + Allow JSON-RPC connections from specified IP address Povoliť JSON-RPC spojenia z určenej IP adresy. - + Send commands to node running on <ip> (default: 127.0.0.1) Poslať príkaz nóde bežiacej na <ip> (predvolené: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) Nastaviť zásobu adries na <n> (predvolené: 100) @@ -2717,12 +2750,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Znovu skenovať reťaz blokov pre chýbajúce transakcie - + Use OpenSSL (https) for JSON-RPC connections Použiť OpenSSL (https) pre JSON-RPC spojenia - + Server certificate file (default: server.cert) Súbor s certifikátom servra (predvolené: server.cert) @@ -2732,22 +2765,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Súkromný kľúč servra (predvolené: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Prijateľné šifry (predvolené: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Táto pomocná správa - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy Pripojenie cez socks proxy @@ -2757,12 +2790,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Povoliť vyhľadávanie DNS pre pridanie nódy a spojenie - + Loading addresses... Načítavanie adries... - + Error loading wallet.dat: Wallet corrupted Chyba načítania wallet.dat: Peňaženka je poškodená @@ -2772,22 +2805,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Chyba načítania wallet.dat: Peňaženka vyžaduje novšiu verziu Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Bolo potrebné prepísať peňaženku: dokončite reštartovaním Bitcoin - + Error loading wallet.dat Chyba načítania wallet.dat - + Invalid -proxy address: '%s' Neplatná adresa proxy: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2797,7 +2830,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2807,7 +2840,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Neplatná suma pre -paytxfee=<amount>: '%s' @@ -2817,17 +2850,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Neplatná suma - + Insufficient funds - + Loading block index... Načítavanie zoznamu blokov... - + Add a node to connect to and attempt to keep the connection open Pridať nódu a pripojiť sa and attempt to keep the connection open @@ -2837,17 +2870,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send Poplatok za kB ktorý treba pridať k odoslanej transakcii - + Loading wallet... Načítavam peňaženku... - + Cannot downgrade wallet @@ -2857,22 +2890,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading Dokončené načítavanie - + To use the %s option - + Error Chyba diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index ecb3342ac..051127788 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -2123,6 +2123,14 @@ Address: %4 do + + WalletModel + + + Send Coins + Слање новца + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 Bitcoin верзија - + Usage: Korišćenje: - + Send command to -server or bitcoind Pošalji naredbu na -server ili bitcoinid @@ -2190,17 +2198,17 @@ Address: %4 Listaj komande - + Get help for a command Zatraži pomoć za komande - + Options: Opcije - + Specify configuration file (default: bitcoin.conf) Potvrdi željeni konfiguracioni fajl (podrazumevani:bitcoin.conf) @@ -2215,7 +2223,7 @@ Address: %4 Gde je konkretni data direktorijum - + Set database cache size in megabytes (default: 25) @@ -2231,12 +2239,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2246,7 +2254,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2266,17 +2274,17 @@ Address: %4 Prihvati komandnu liniju i JSON-RPC komande - + Run in the background as a daemon and accept commands Radi u pozadini kao daemon servis i prihvati komande - + Use the test network Koristi testnu mrežu - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2420,11 +2428,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2511,7 +2514,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2526,7 +2529,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2536,17 +2539,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2555,6 +2558,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2630,6 +2643,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2641,7 +2659,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2681,32 +2714,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections Lozinka za JSON-RPC konekcije - + Allow JSON-RPC connections from specified IP address Dozvoli JSON-RPC konekcije sa posebne IP adrese - + Send commands to node running on <ip> (default: 127.0.0.1) Pošalji komande to nodu koji radi na <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) Odredi veličinu zaštićenih ključeva na <n> (default: 100) @@ -2716,12 +2749,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Ponovo skeniraj lanac blokova za nedostajuće transakcije iz novčanika - + Use OpenSSL (https) for JSON-RPC connections Koristi OpenSSL (https) za JSON-RPC konekcije - + Server certificate file (default: server.cert) @@ -2731,22 +2764,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. privatni ključ za Server (podrazumevan: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Prihvatljive cifre (podrazumevano: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Ova poruka Pomoći - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2756,12 +2789,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... učitavam adrese.... - + Error loading wallet.dat: Wallet corrupted @@ -2771,22 +2804,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2796,7 +2829,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2806,7 +2839,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2816,17 +2849,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... Učitavam blok indeksa... - + Add a node to connect to and attempt to keep the connection open @@ -2836,17 +2869,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... Новчаник се учитава... - + Cannot downgrade wallet @@ -2856,22 +2889,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... Ponovo skeniram... - + Done loading Završeno učitavanje - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index f57ce9699..461c84f1c 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -2133,6 +2133,14 @@ Adress: %4 till + + WalletModel + + + Send Coins + Skicka pengar + + WalletView @@ -2184,12 +2192,12 @@ Adress: %4 Bitcoin version - + Usage: Användning: - + Send command to -server or bitcoind Skicka kommando till -server eller bitcoind @@ -2199,17 +2207,17 @@ Adress: %4 Lista kommandon - + Get help for a command Få hjälp med ett kommando - + Options: Inställningar: - + Specify configuration file (default: bitcoin.conf) Ange konfigurationsfil (förvalt: bitcoin.conf) @@ -2224,7 +2232,7 @@ Adress: %4 Ange katalog för data - + Set database cache size in megabytes (default: 25) Sätt databas cache storleken i megabyte (förvalt: 25) @@ -2239,12 +2247,12 @@ Adress: %4 Ha som mest <n> anslutningar till andra klienter (förvalt: 125) - + Connect to a node to retrieve peer addresses, and disconnect Anslut till en nod för att hämta klientadresser, och koppla från - + Specify your own public address Ange din egen publika adress @@ -2254,7 +2262,7 @@ Adress: %4 Tröskelvärde för att koppla ifrån klienter som missköter sig (förvalt: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Antal sekunder att hindra klienter som missköter sig från att ansluta (förvalt: 86400) @@ -2274,17 +2282,17 @@ Adress: %4 Tillåt kommandon från kommandotolken och JSON-RPC-kommandon - + Run in the background as a daemon and accept commands Kör i bakgrunden som tjänst och acceptera kommandon - + Use the test network Använd testnätverket - + Accept connections from outside (default: 1 if no -proxy or -connect) Acceptera anslutningar utifrån (förvalt: 1 om ingen -proxy eller -connect) @@ -2438,11 +2446,6 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Error: Disk space is low! Fel: Hårddiskutrymme är lågt! - - - Error: Transaction creation failed! - Fel: Transaktionen gick inte att skapa! - Error: Wallet locked, unable to create transaction! @@ -2529,7 +2532,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Hur grundlig blockverifikationen är (0-4, förvalt: 3) - + Not enough file descriptors available. Inte tillräckligt med filbeskrivningar tillgängliga. @@ -2544,7 +2547,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Ange antalet trådar för att hantera RPC anrop (standard: 4) - + Verifying blocks... Verifierar block... @@ -2554,17 +2557,17 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Verifierar plånboken... - + Imports blocks from external blk000??.dat file Importerar block från extern blk000??.dat fil - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Ange antalet skriptkontrolltrådar (upp till 16, 0 = auto, <0 = lämna så många kärnor lediga, förval: 0) - + Information Information @@ -2573,6 +2576,16 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Invalid -tor address: '%s' Ogiltig -tor adress: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ogiltigt belopp för -minrelaytxfee=<belopp>: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + Ogiltigt belopp för -mintxfee=<belopp>: '%s' + Maintain a full transaction index (default: 0) @@ -2648,6 +2661,11 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Shrink debug.log file on client startup (default: 1 when no -debug) Krymp debug.log filen vid klient start (förvalt: 1 vid ingen -debug) + + + Signing transaction failed + Signering av transaktion misslyckades + Specify connection timeout in milliseconds (default: 5000) @@ -2659,7 +2677,22 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Systemfel: - + + Transaction amount too small + Transaktions belopp för liten + + + + Transaction amounts must be positive + Transaktionens belopp måste vara positiva + + + + Transaction too large + Transaktionen är för stor + + + Use UPnP to map the listening port (default: 0) Använd UPnP för att mappa den lyssnande porten (förvalt: 0) @@ -2699,32 +2732,32 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo wallet.dat korrupt, räddning misslyckades - + Password for JSON-RPC connections Lösenord för JSON-RPC-anslutningar - + Allow JSON-RPC connections from specified IP address Tillåt JSON-RPC-anslutningar från specifika IP-adresser - + Send commands to node running on <ip> (default: 127.0.0.1) Skicka kommandon till klient på <ip> (förvalt: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) Exekvera kommando när det bästa blocket ändras (%s i cmd är utbytt av blockhash) - + Upgrade wallet to latest format Uppgradera plånboken till senaste formatet - + Set key pool size to <n> (default: 100) Sätt storleken på nyckelpoolen till <n> (förvalt: 100) @@ -2734,12 +2767,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Sök i blockkedjan efter saknade plånboks transaktioner - + Use OpenSSL (https) for JSON-RPC connections Använd OpenSSL (https) för JSON-RPC-anslutningar - + Server certificate file (default: server.cert) Serverns certifikatfil (förvalt: server.cert) @@ -2749,22 +2782,22 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Serverns privata nyckel (förvalt: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Accepterade krypteringsalgoritmer (förvalt: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Det här hjälp medelandet - + Unable to bind to %s on this computer (bind returned error %d, %s) Det går inte att binda till %s på den här datorn (bind returnerade felmeddelande %d, %s) - + Connect through socks proxy Anslut genom socks-proxy @@ -2774,12 +2807,12 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Tillåt DNS-sökningar för -addnode, -seednode och -connect - + Loading addresses... Laddar adresser... - + Error loading wallet.dat: Wallet corrupted Fel vid inläsningen av wallet.dat: Plånboken är skadad @@ -2789,22 +2822,22 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Fel vid inläsningen av wallet.dat: Plånboken kräver en senare version av Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete Plånboken behöver skrivas om: Starta om Bitcoin för att färdigställa - + Error loading wallet.dat Fel vid inläsning av plånboksfilen wallet.dat - + Invalid -proxy address: '%s' Ogiltig -proxy adress: '%s' - + Unknown network specified in -onlynet: '%s' Okänt nätverk som anges i -onlynet: '%s' @@ -2814,7 +2847,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Okänd -socks proxy version begärd: %i - + Cannot resolve -bind address: '%s' Kan inte matcha -bind adress: '%s' @@ -2824,7 +2857,7 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Kan inte matcha -externalip adress: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' Ogiltigt belopp för -paytxfee=<belopp>:'%s' @@ -2834,17 +2867,17 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Ogiltig mängd - + Insufficient funds Otillräckligt med bitcoins - + Loading block index... Laddar blockindex... - + Add a node to connect to and attempt to keep the connection open Lägg till en nod att koppla upp mot och försök att hålla anslutningen öppen @@ -2854,17 +2887,17 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Det går inte att binda till %s på den här datorn. Bitcoin är förmodligen redan igång. - + Fee per KB to add to transactions you send Avgift per KB att lägga till på transaktioner du skickar - + Loading wallet... Laddar plånbok... - + Cannot downgrade wallet Kan inte nedgradera plånboken @@ -2874,22 +2907,22 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo Kan inte skriva standardadress - + Rescanning... Söker igen... - + Done loading Klar med laddning - + To use the %s option Att använda %s alternativet - + Error Fel diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index ad220f14a..d808b014d 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -2123,6 +2123,14 @@ Address: %4 + + WalletModel + + + Send Coins + + + WalletView @@ -2174,12 +2182,12 @@ Address: %4 - + Usage: - + Send command to -server or bitcoind @@ -2189,17 +2197,17 @@ Address: %4 - + Get help for a command - + Options: - + Specify configuration file (default: bitcoin.conf) @@ -2214,7 +2222,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) @@ -2229,12 +2237,12 @@ Address: %4 - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2244,7 +2252,7 @@ Address: %4 - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) @@ -2264,17 +2272,17 @@ Address: %4 - + Run in the background as a daemon and accept commands - + Use the test network - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2418,11 +2426,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! - - - Error: Transaction creation failed! - - Error: Wallet locked, unable to create transaction! @@ -2509,7 +2512,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2524,7 +2527,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2534,17 +2537,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information @@ -2553,6 +2556,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2628,6 +2641,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2639,7 +2657,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) @@ -2679,32 +2712,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Password for JSON-RPC connections - + Allow JSON-RPC connections from specified IP address - + Send commands to node running on <ip> (default: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format - + Set key pool size to <n> (default: 100) @@ -2714,12 +2747,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Use OpenSSL (https) for JSON-RPC connections - + Server certificate file (default: server.cert) @@ -2729,22 +2762,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message - + Unable to bind to %s on this computer (bind returned error %d, %s) - + Connect through socks proxy @@ -2754,12 +2787,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Loading addresses... - + Error loading wallet.dat: Wallet corrupted @@ -2769,22 +2802,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Wallet needed to be rewritten: restart Bitcoin to complete - + Error loading wallet.dat - + Invalid -proxy address: '%s' - + Unknown network specified in -onlynet: '%s' @@ -2794,7 +2827,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2804,7 +2837,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' @@ -2814,17 +2847,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Insufficient funds - + Loading block index... - + Add a node to connect to and attempt to keep the connection open @@ -2834,17 +2867,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Fee per KB to add to transactions you send - + Loading wallet... - + Cannot downgrade wallet @@ -2854,22 +2887,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Rescanning... - + Done loading - + To use the %s option - + Error diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index ec83848fb..00888ae72 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -2132,6 +2132,14 @@ Adres: %4 ilâ + + WalletModel + + + Send Coins + Bitcoin yolla + + WalletView @@ -2183,12 +2191,12 @@ Adres: %4 Bitcoin sürümü - + Usage: Kullanım: - + Send command to -server or bitcoind -server ya da bitcoind'ye komut gönder @@ -2198,17 +2206,17 @@ Adres: %4 Komutları listele - + Get help for a command Bir komut için yardım al - + Options: Seçenekler: - + Specify configuration file (default: bitcoin.conf) Yapılandırma dosyası belirt (varsayılan: bitcoin.conf) @@ -2223,7 +2231,7 @@ Adres: %4 Veri dizinini belirt - + Set database cache size in megabytes (default: 25) Veritabanı önbellek boyutunu megabayt olarak belirt (varsayılan: 25) @@ -2238,12 +2246,12 @@ Adres: %4 Eşler ile en çok <n> adet bağlantı kur (varsayılan: 125) - + Connect to a node to retrieve peer addresses, and disconnect Eş adresleri elde etmek için bir düğüme bağlan ve ardından bağlantıyı kes - + Specify your own public address Kendi genel adresinizi tanımlayın @@ -2253,7 +2261,7 @@ Adres: %4 Aksaklık gösteren eşlerle bağlantıyı kesme sınırı (varsayılan: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Aksaklık gösteren eşlerle yeni bağlantıları engelleme süresi, saniye olarak (varsayılan: 86400) @@ -2273,17 +2281,17 @@ Adres: %4 Konut satırı ve JSON-RPC komutlarını kabul et - + Run in the background as a daemon and accept commands Arka planda daemon (servis) olarak çalış ve komutları kabul et - + Use the test network Deneme şebekesini kullan - + Accept connections from outside (default: 1 if no -proxy or -connect) Dışarıdan gelen bağlantıları kabul et (varsayılan: -proxy veya -connect yoksa 1) @@ -2437,11 +2445,6 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Error: Disk space is low! Hata: Disk alanı düşük! - - - Error: Transaction creation failed! - Hata: Muamele oluşturması başarısız oldu! - Error: Wallet locked, unable to create transaction! @@ -2528,7 +2531,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blok kontrolünün ne kadar derin olacağı (0 ilâ 4, varsayılan: 3) - + Not enough file descriptors available. Kafi derecede dosya tanımlayıcıları mevcut değil. @@ -2543,7 +2546,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com RPC aramaları için iş parçacığı sayısını belirle (varsayılan: 4) - + Verifying blocks... Bloklar kontrol ediliyor... @@ -2553,17 +2556,17 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Cüzdan kontrol ediliyor... - + Imports blocks from external blk000??.dat file Harici blk000??.dat dosyasından blokları içe aktarır - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) Betik kontrolü iş parçacığı sayısını belirt (azami 16, 0 = otomatik, <0 = bu sayıda çekirdeği boş bırak, varsayılan: 0) - + Information Bilgi @@ -2572,6 +2575,16 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Invalid -tor address: '%s' Geçersiz -tor adresi: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + -minrelaytxfee=<amount> için geçersiz meblağ: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + -mintxfee=<amount> için geçersiz meblağ: '%s' + Maintain a full transaction index (default: 0) @@ -2647,6 +2660,11 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Shrink debug.log file on client startup (default: 1 when no -debug) İstemci başlatıldığında debug.log dosyasını küçült (varsayılan: -debug bulunmadığında 1) + + + Signing transaction failed + Muamelenin imzalanması başarısız oldu + Specify connection timeout in milliseconds (default: 5000) @@ -2658,7 +2676,22 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Sistem hatası: - + + Transaction amount too small + Muamele meblağı çok düşük + + + + Transaction amounts must be positive + Muamele tutarının pozitif olması lazımdır + + + + Transaction too large + Muamele çok büyük + + + Use UPnP to map the listening port (default: 0) Dinlenecek portu haritalamak için UPnP kullan (varsayılan: 0) @@ -2698,32 +2731,32 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com wallet.dat bozuk, geri kazanım başarısız oldu - + Password for JSON-RPC connections JSON-RPC bağlantıları için parola - + Allow JSON-RPC connections from specified IP address Belirtilen İP adresinden JSON-RPC bağlantılarını kabul et - + Send commands to node running on <ip> (default: 127.0.0.1) Şu <ip> adresinde (varsayılan: 127.0.0.1) çalışan düğüme komut yolla - + Execute command when the best block changes (%s in cmd is replaced by block hash) En iyi blok değiştiğinde komutu çalıştır (komut için %s parametresi blok hash değeri ile değiştirilecektir) - + Upgrade wallet to latest format Cüzdanı en yeni biçime güncelle - + Set key pool size to <n> (default: 100) Anahtar alan boyutunu <n> değerine ayarla (varsayılan: 100) @@ -2733,12 +2766,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Blok zincirini eksik cüzdan muameleleri için tekrar tara - + Use OpenSSL (https) for JSON-RPC connections JSON-RPC bağlantıları için OpenSSL (https) kullan - + Server certificate file (default: server.cert) Sunucu sertifika dosyası (varsayılan: server.cert) @@ -2748,22 +2781,22 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Sunucu özel anahtarı (varsayılan: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Kabul edilebilir şifreler (varsayılan: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Bu yardım mesajı - + Unable to bind to %s on this computer (bind returned error %d, %s) Bu bilgisayarda %s unsuruna bağlanılamadı. (bind şu hatayı iletti: %d, %s) - + Connect through socks proxy Socks vekil sunucusu vasıtasıyla bağlan @@ -2773,12 +2806,12 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com -addnode, -seednode ve -connect için DNS aramalarına izin ver - + Loading addresses... Adresler yükleniyor... - + Error loading wallet.dat: Wallet corrupted wallet.dat dosyasının yüklenmesinde hata oluştu: bozuk cüzdan @@ -2788,22 +2821,22 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com wallet.dat dosyasının yüklenmesinde hata oluştu: cüzdanın daha yeni bir Bitcoin sürümüne ihtiyacı var - + Wallet needed to be rewritten: restart Bitcoin to complete Cüzdanın tekrar yazılması gerekiyordu: işlemi tamamlamak için Bitcoin'i yeniden başlatınız - + Error loading wallet.dat wallet.dat dosyasının yüklenmesinde hata oluştu - + Invalid -proxy address: '%s' Geçersiz -proxy adresi: '%s' - + Unknown network specified in -onlynet: '%s' -onlynet için bilinmeyen bir şebeke belirtildi: '%s' @@ -2813,7 +2846,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Bilinmeyen bir -socks vekil sürümü talep edildi: %i - + Cannot resolve -bind address: '%s' -bind adresi çözümlenemedi: '%s' @@ -2823,7 +2856,7 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com -externalip adresi çözümlenemedi: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' -paytxfee=<miktar> için geçersiz miktar: '%s' @@ -2833,17 +2866,17 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Geçersiz miktar - + Insufficient funds Yetersiz bakiye - + Loading block index... Blok indeksi yükleniyor... - + Add a node to connect to and attempt to keep the connection open Bağlanılacak düğüm ekle ve bağlantıyı zinde tutmaya çalış @@ -2853,17 +2886,17 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Bu bilgisayarda %s unsuruna bağlanılamadı. Bitcoin muhtemelen hâlihazırda çalışmaktadır. - + Fee per KB to add to transactions you send Yolladığınız muameleler için eklenecek KB başı ücret - + Loading wallet... Cüzdan yükleniyor... - + Cannot downgrade wallet Cüzdan eski biçime geri alınamaz @@ -2873,22 +2906,22 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Varsayılan adres yazılamadı - + Rescanning... Yeniden tarama... - + Done loading Yükleme tamamlandı - + To use the %s option %s seçeneğini kullanmak için - + Error Hata diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index 63faf67ec..ac0096ed6 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -2132,6 +2132,14 @@ Address: %4 до + + WalletModel + + + Send Coins + Відправити + + WalletView @@ -2183,12 +2191,12 @@ Address: %4 Версія - + Usage: Використання: - + Send command to -server or bitcoind Відправити команду серверу -server чи демону @@ -2198,17 +2206,17 @@ Address: %4 Список команд - + Get help for a command Отримати довідку по команді - + Options: Параметри: - + Specify configuration file (default: bitcoin.conf) Вкажіть файл конфігурації (типово: bitcoin.conf) @@ -2223,7 +2231,7 @@ Address: %4 Вкажіть робочий каталог - + Set database cache size in megabytes (default: 25) Встановити розмір кешу бази даних в мегабайтах (типово: 25) @@ -2238,12 +2246,12 @@ Address: %4 Підтримувати не більше <n> зв'язків з колегами (типово: 125) - + Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address @@ -2253,7 +2261,7 @@ Address: %4 Поріг відключення неправильно під'єднаних пірів (типово: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Максимальній розмір вхідного буферу на одне з'єднання (типово: 86400) @@ -2273,17 +2281,17 @@ Address: %4 Приймати команди із командного рядка та команди JSON-RPC - + Run in the background as a daemon and accept commands Запустити в фоновому режимі (як демон) та приймати команди - + Use the test network Використовувати тестову мережу - + Accept connections from outside (default: 1 if no -proxy or -connect) @@ -2427,11 +2435,6 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Error: Disk space is low! Помилка: Мало вільного місця на диску! - - - Error: Transaction creation failed! - Помилка: Не вдалося створити транзакцію! - Error: Wallet locked, unable to create transaction! @@ -2518,7 +2521,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Not enough file descriptors available. @@ -2533,7 +2536,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Verifying blocks... @@ -2543,17 +2546,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Imports blocks from external blk000??.dat file Імпорт блоків з зовнішнього файлу blk000??.dat - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information Інформація @@ -2562,6 +2565,16 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid -tor address: '%s' Помилка в адресі -tor: «%s» + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2637,6 +2650,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Shrink debug.log file on client startup (default: 1 when no -debug) Стискати файл debug.log під час старту клієнта (типово: 1 коли відсутутній параметр -debug) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2648,7 +2666,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Системна помилка: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) Намагатись використовувати UPnP для відображення порту, що прослуховується на роутері (default: 0) @@ -2688,32 +2721,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. wallet.dat пошкоджено, відновлення не вдалося - + Password for JSON-RPC connections Пароль для JSON-RPC-з'єднань - + Allow JSON-RPC connections from specified IP address Дозволити JSON-RPC-з'єднання з вказаної IP-адреси - + Send commands to node running on <ip> (default: 127.0.0.1) Відправляти команди на вузол, запущений на <ip> (типово: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) - + Upgrade wallet to latest format Модернізувати гаманець до останнього формату - + Set key pool size to <n> (default: 100) Встановити розмір пулу ключів <n> (типово: 100) @@ -2723,12 +2756,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Пересканувати ланцюжок блоків, в пошуку втрачених транзакцій - + Use OpenSSL (https) for JSON-RPC connections Використовувати OpenSSL (https) для JSON-RPC-з'єднань - + Server certificate file (default: server.cert) Файл сертифіката сервера (типово: server.cert) @@ -2738,22 +2771,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Закритий ключ сервера (типово: server.pem) - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) Допустимі шифри (типово: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message Дана довідка - + Unable to bind to %s on this computer (bind returned error %d, %s) Неможливо прив'язати до порту %s на цьому комп'ютері (bind returned error %d, %s) - + Connect through socks proxy Підключитись через SOCKS-проксі @@ -2763,12 +2796,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Дозволити пошук в DNS для команд -addnode, -seednode та -connect - + Loading addresses... Завантаження адрес... - + Error loading wallet.dat: Wallet corrupted Помилка при завантаженні wallet.dat: Гаманець пошкоджено @@ -2778,22 +2811,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Помилка при завантаженні wallet.dat: Гаманець потребує новішої версії Біткоін-клієнта - + Wallet needed to be rewritten: restart Bitcoin to complete Потрібно перезаписати гаманець: перезапустіть Біткоін-клієнт для завершення - + Error loading wallet.dat Помилка при завантаженні wallet.dat - + Invalid -proxy address: '%s' Помилка в адресі проксі-сервера: «%s» - + Unknown network specified in -onlynet: '%s' Невідома мережа вказана в -onlynet: «%s» @@ -2803,7 +2836,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Cannot resolve -bind address: '%s' @@ -2813,7 +2846,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. - + Invalid amount for -paytxfee=<amount>: '%s' Помилка у величині комісії -paytxfee=<amount>: «%s» @@ -2823,17 +2856,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Некоректна кількість - + Insufficient funds Недостатньо коштів - + Loading block index... Завантаження індексу блоків... - + Add a node to connect to and attempt to keep the connection open Додати вузол до підключення і лишити його відкритим @@ -2843,17 +2876,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Неможливо прив'язати до порту %s на цьому комп'ютері. Можливо гаманець вже запущено. - + Fee per KB to add to transactions you send Комісія за КБ - + Loading wallet... Завантаження гаманця... - + Cannot downgrade wallet @@ -2863,22 +2896,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Неможливо записати типову адресу - + Rescanning... Сканування... - + Done loading Завантаження завершене - + To use the %s option - + Error Помилка diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 163b6ddaa..31895364f 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -2133,6 +2133,14 @@ Address: %4 + + WalletModel + + + Send Coins + 发送比特币 + + WalletView @@ -2184,12 +2192,12 @@ Address: %4 比特币版本 - + Usage: 使用: - + Send command to -server or bitcoind 发送命令到服务器或者 bitcoind @@ -2201,19 +2209,19 @@ Address: %4 - + Get help for a command 获得某条命令的帮助 - + Options: 选项: - + Specify configuration file (default: bitcoin.conf) 指定配置文件 (默认为 bitcoin.conf) @@ -2231,7 +2239,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) 设置数据库缓冲区大小 (缺省: 25MB) @@ -2246,12 +2254,12 @@ Address: %4 最大连接数 <n> (缺省: 125) - + Connect to a node to retrieve peer addresses, and disconnect 连接一个节点并获取对端地址, 然后断开连接 - + Specify your own public address 指定您的公共地址 @@ -2261,7 +2269,7 @@ Address: %4 Threshold for disconnecting misbehaving peers (缺省: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) Number of seconds to keep misbehaving peers from reconnecting (缺省: 86400) @@ -2282,20 +2290,20 @@ Address: %4 - + Run in the background as a daemon and accept commands 在后台运行并接受命令 - + Use the test network 使用测试网络 - + Accept connections from outside (default: 1 if no -proxy or -connect) 接受来自外部的连接 (缺省: 如果不带 -proxy or -connect 参数设置为1) @@ -2449,11 +2457,6 @@ rpcpassword=%s Error: Disk space is low! 错误:磁盘剩余空间低! - - - Error: Transaction creation failed! - 错误:创建交易失败! - Error: Wallet locked, unable to create transaction! @@ -2540,7 +2543,7 @@ rpcpassword=%s How thorough the block verification is (0-4, default: 3) - + Not enough file descriptors available. @@ -2555,7 +2558,7 @@ rpcpassword=%s 设置使用调用服务 RPC 的线程数量(默认:4) - + Verifying blocks... 正在验证数据库的完整性... @@ -2565,17 +2568,17 @@ rpcpassword=%s 正在检测钱包的完整性... - + Imports blocks from external blk000??.dat file 从blk000??.dat文件导入数据块 - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information 信息 @@ -2584,6 +2587,16 @@ rpcpassword=%s Invalid -tor address: '%s' 非法的 -tor 地址:'%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + Maintain a full transaction index (default: 0) @@ -2659,6 +2672,11 @@ rpcpassword=%s Shrink debug.log file on client startup (default: 1 when no -debug) 客户端启动时压缩debug.log文件(缺省:no-debug模式时为1) + + + Signing transaction failed + + Specify connection timeout in milliseconds (default: 5000) @@ -2670,7 +2688,22 @@ rpcpassword=%s 系统错误: - + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + Use UPnP to map the listening port (default: 0) 使用UPnp映射监听端口(缺省: 0) @@ -2711,35 +2744,35 @@ rpcpassword=%s 钱包文件wallet.dat损坏,抢救备份失败 - + Password for JSON-RPC connections JSON-RPC连接密码 - + Allow JSON-RPC connections from specified IP address 允许从指定IP接受到的JSON-RPC连接 - + Send commands to node running on <ip> (default: 127.0.0.1) 向IP地址为 <ip> 的节点发送指令 (缺省: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) 当最佳数据块变化时执行命令 (命令行中的 %s 会被替换成数据块哈希值) - + Upgrade wallet to latest format 将钱包升级到最新的格式 - + Set key pool size to <n> (default: 100) 设置密钥池大小为 <n> (缺省: 100) @@ -2751,12 +2784,12 @@ rpcpassword=%s - + Use OpenSSL (https) for JSON-RPC connections 为 JSON-RPC 连接使用 OpenSSL (https)连接 - + Server certificate file (default: server.cert) 服务器证书 (默认为 server.cert) @@ -2768,24 +2801,24 @@ rpcpassword=%s - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) 可接受的加密器 (默认为 TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message 该帮助信息 - + Unable to bind to %s on this computer (bind returned error %d, %s) 无法绑定本机端口 %s (返回错误消息 %d, %s) - + Connect through socks proxy 通过 socks 代理连接 @@ -2795,12 +2828,12 @@ rpcpassword=%s 使用 -addnode, -seednode 和 -connect选项时允许DNS查找 - + Loading addresses... 正在加载地址... - + Error loading wallet.dat: Wallet corrupted wallet.dat钱包文件加载错误:钱包损坏 @@ -2810,22 +2843,22 @@ rpcpassword=%s wallet.dat钱包文件加载错误:请升级到最新Bitcoin客户端 - + Wallet needed to be rewritten: restart Bitcoin to complete 钱包文件需要重写:请退出并重新启动Bitcoin客户端 - + Error loading wallet.dat wallet.dat钱包文件加载错误 - + Invalid -proxy address: '%s' 非法的代理地址: '%s' - + Unknown network specified in -onlynet: '%s' 被指定的是未知网络 -onlynet: '%s' @@ -2835,7 +2868,7 @@ rpcpassword=%s 被指定的是未知socks代理版本: %i - + Cannot resolve -bind address: '%s' 无法解析 -bind 端口地址: '%s' @@ -2845,7 +2878,7 @@ rpcpassword=%s 无法解析 -externalip 地址: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' 非法金额 -paytxfee=<amount>: '%s' @@ -2855,17 +2888,17 @@ rpcpassword=%s 金额不对 - + Insufficient funds 金额不足 - + Loading block index... 加载数据块索引... - + Add a node to connect to and attempt to keep the connection open 添加节点并与其保持连接 @@ -2875,17 +2908,17 @@ rpcpassword=%s 无法在本机绑定 %s 端口 . 比特币客户端软件可能已经在运行. - + Fee per KB to add to transactions you send 每发送1KB交易所需的费用 - + Loading wallet... 正在加载钱包... - + Cannot downgrade wallet 无法降级钱包格式 @@ -2895,22 +2928,22 @@ rpcpassword=%s 无法写入缺省地址 - + Rescanning... 正在重新扫描... - + Done loading 加载完成 - + To use the %s option 使用 %s 选项 - + Error 错误 diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index c98cd6a53..94e642758 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -810,7 +810,7 @@ Address: %4 Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + 非必要的交易手續費, 以 kB 為計費單位, 且有助於縮短你的交易處理時間. 大部份交易資料的大小是 1 kB. @@ -2132,12 +2132,20 @@ Address: %4 + + WalletModel + + + Send Coins + 付錢 + + WalletView &Export - + 匯出 @@ -2183,12 +2191,12 @@ Address: %4 位元幣版本 - + Usage: 用法: - + Send command to -server or bitcoind 送指令給 -server 或 bitcoind @@ -2200,19 +2208,19 @@ Address: %4 - + Get help for a command 取得指令說明 - + Options: 選項: - + Specify configuration file (default: bitcoin.conf) 指定設定檔 (預設: bitcoin.conf) @@ -2230,7 +2238,7 @@ Address: %4 - + Set database cache size in megabytes (default: 25) 設定資料庫快取大小為多少百萬位元組(MB, 預設: 25) @@ -2245,12 +2253,12 @@ Address: %4 維持與節點連線數的上限為 <n> 個 (預設: 125) - + Connect to a node to retrieve peer addresses, and disconnect 連線到某個節點以取得其它節點的位址, 然後斷線 - + Specify your own public address 指定自己公開的位址 @@ -2260,7 +2268,7 @@ Address: %4 與亂搞的節點斷線的臨界值 (預設: 100) - + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) 避免與亂搞的節點連線的秒數 (預設: 86400) @@ -2281,18 +2289,18 @@ Address: %4 - + Run in the background as a daemon and accept commands 以背景程式執行並接受指令 - + Use the test network 使用測試網路 - + Accept connections from outside (default: 1 if no -proxy or -connect) 是否接受外來連線 (預設: 當沒有 -proxy 或 -connect 時預設為 1) @@ -2447,11 +2455,6 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Error: Disk space is low! 錯誤: 磁碟空間很少! - - - Error: Transaction creation failed! - 錯誤: 交易產生失敗! - Error: Wallet locked, unable to create transaction! @@ -2525,7 +2528,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Generate coins (default: 0) - + 生產位元幣 (預設值: 0) @@ -2538,9 +2541,9 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 區塊檢查的仔細程度 (0 至 4, 預設: 3) - + Not enough file descriptors available. - + 檔案描述器不足. @@ -2553,7 +2556,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 設定處理 RPC 服務請求的執行緒數目 (預設為 4) - + Verifying blocks... 驗證區塊資料中... @@ -2563,17 +2566,17 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 驗證錢包資料中... - + Imports blocks from external blk000??.dat file 從其它來源的 blk000??.dat 檔匯入區塊 - + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Information 資訊 @@ -2582,6 +2585,16 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Invalid -tor address: '%s' 無效的 -tor 位址: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + 設定 -minrelaytxfee=<金額> 的金額無效: '%s' + + + + Invalid amount for -mintxfee=<amount>: '%s' + 設定 -mintxfee=<amount> 的金額無效: '%s' + Maintain a full transaction index (default: 0) @@ -2657,6 +2670,11 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Shrink debug.log file on client startup (default: 1 when no -debug) 客戶端軟體啓動時將 debug.log 檔縮小 (預設: 當沒有 -debug 時為 1) + + + Signing transaction failed + 簽署交易失敗 + Specify connection timeout in milliseconds (default: 5000) @@ -2668,7 +2686,22 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 系統錯誤: - + + Transaction amount too small + 交易金額太小 + + + + Transaction amounts must be positive + 交易金額必須是正的 + + + + Transaction too large + 交易位元量太大 + + + Use UPnP to map the listening port (default: 0) 是否使用通用即插即用(UPnP)協定來設定聽候連線的通訊埠 (預設: 0) @@ -2708,33 +2741,33 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 錢包檔 weallet.dat 壞掉了, 拯救失敗 - + Password for JSON-RPC connections JSON-RPC 連線密碼 - + Allow JSON-RPC connections from specified IP address 只允許從指定網路位址來的 JSON-RPC 連線 - + Send commands to node running on <ip> (default: 127.0.0.1) 送指令給在 <ip> 的節點 (預設: 127.0.0.1) - + Execute command when the best block changes (%s in cmd is replaced by block hash) 當最新區塊改變時所要執行的指令 (指令中的 %s 會被取代為區塊的雜湊值) - + Upgrade wallet to latest format 將錢包升級成最新的格式 - + Set key pool size to <n> (default: 100) 設定密鑰池大小為 <n> (預設: 100) @@ -2745,13 +2778,13 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 重新掃描區塊鎖鏈, 以尋找錢包所遺漏的交易. - + Use OpenSSL (https) for JSON-RPC connections 於 JSON-RPC 連線使用 OpenSSL (https) - + Server certificate file (default: server.cert) 伺服器憑證檔 (預設: server.cert) @@ -2763,24 +2796,24 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) 可以接受的加密法 (預設: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) - + This help message 此協助訊息 - + Unable to bind to %s on this computer (bind returned error %d, %s) 無法和這台電腦上的 %s 繫結 (繫結回傳錯誤 %d, %s) - + Connect through socks proxy 透過 SOCKS 代理伺服器連線 @@ -2790,12 +2823,12 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 允許對 -addnode, -seednode, -connect 的參數使用域名查詢 - + Loading addresses... 載入位址中... - + Error loading wallet.dat: Wallet corrupted 載入檔案 wallet.dat 失敗: 錢包壞掉了 @@ -2805,22 +2838,22 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 載入檔案 wallet.dat 失敗: 此錢包需要新版的 Bitcoin - + Wallet needed to be rewritten: restart Bitcoin to complete 錢包需要重寫: 請重啟位元幣來完成 - + Error loading wallet.dat 載入檔案 wallet.dat 失敗 - + Invalid -proxy address: '%s' 無效的 -proxy 位址: '%s' - + Unknown network specified in -onlynet: '%s' 在 -onlynet 指定了不明的網路別: '%s' @@ -2830,7 +2863,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 在 -socks 指定了不明的代理協定版本: %i - + Cannot resolve -bind address: '%s' 無法解析 -bind 位址: '%s' @@ -2840,7 +2873,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無法解析 -externalip 位址: '%s' - + Invalid amount for -paytxfee=<amount>: '%s' 設定 -paytxfee=<金額> 的金額無效: '%s' @@ -2850,17 +2883,17 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無效的金額 - + Insufficient funds 累積金額不足 - + Loading block index... 載入區塊索引中... - + Add a node to connect to and attempt to keep the connection open 加入一個要連線的節線, 並試著保持對它的連線暢通 @@ -2870,17 +2903,17 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無法和這台電腦上的 %s 繫結. 也許位元幣已經在執行了. - + Fee per KB to add to transactions you send 交易付款時每 KB 的交易手續費 - + Loading wallet... 載入錢包中... - + Cannot downgrade wallet 無法將錢包格式降級 @@ -2890,22 +2923,22 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com 無法寫入預設位址 - + Rescanning... 重新掃描中... - + Done loading 載入完成 - + To use the %s option 為了要使用 %s 選項 - + Error 錯誤 From 4332be71a2b15315ddc299e2f3695054df30eb95 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 9 May 2013 09:56:58 -0400 Subject: [PATCH 32/69] Link with boost_chrono library on OSX Compiling on my OSX 10.6 build machine, I get: Undefined symbols: "boost::chrono::steady_clock::now()", referenced from: boost::cv_status boost::condition_variable::wait_for >(boost::unique_lock&, boost::chrono::duration > const&)in bitcoinrpc.o Linking against the boost_chrono fixes the issue. Windows builds already link against boost_chrono; Linux doesn't, but compiles (on pull-tester / gitian, at least). --- bitcoin-qt.pro | 1 + src/makefile.osx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index d938c07c4..07eadb5db 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -411,6 +411,7 @@ LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX win32:LIBS += -lws2_32 -lshlwapi -lmswsock -lole32 -loleaut32 -luuid -lgdi32 LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX win32:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX +macx:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX contains(RELEASE, 1) { !win32:!macx { diff --git a/src/makefile.osx b/src/makefile.osx index af12731fa..50279fdb0 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -36,6 +36,7 @@ LIBS += \ $(DEPSDIR)/lib/libboost_filesystem-mt.a \ $(DEPSDIR)/lib/libboost_program_options-mt.a \ $(DEPSDIR)/lib/libboost_thread-mt.a \ + $(DEPSDIR)/lib/libboost_chrono-mt.a \ $(DEPSDIR)/lib/libssl.a \ $(DEPSDIR)/lib/libcrypto.a \ -lz @@ -48,6 +49,7 @@ LIBS += \ -lboost_filesystem-mt \ -lboost_program_options-mt \ -lboost_thread-mt \ + -lboost_chrono-mt \ -lssl \ -lcrypto \ -lz From 8f6709076ecae70e970ae3baae215bf67e5a4e5c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Fri, 10 May 2013 09:37:56 -0400 Subject: [PATCH 33/69] Release notes for 0.8.2rc1 --- doc/release-notes.txt | 167 +++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 93 deletions(-) diff --git a/doc/release-notes.txt b/doc/release-notes.txt index 414d5d68c..36b2f7530 100644 --- a/doc/release-notes.txt +++ b/doc/release-notes.txt @@ -1,99 +1,80 @@ (note: this is a temporary file, to be added-to by anybody, and deleted at release time) -Building this from - - $ git shortlog --no-merges v0.7.1.. - -Incompatible Changes --------------------- - -This release no longer maintains a full index of historical transaction ids -by default, so looking up an arbitrary transaction using the getrawtransaction -RPC call will not work. If you need that functionality, you must run once -with -txindex -reindex to rebuild block-chain indices (see below for more -details). - -Improvements ------------- - -Mac and Windows binaries are signed with certificates owned by the Bitcoin -Foundation, to be compatible with the new security features in OSX 10.8 and -Windows 8. - -LevelDB, a fast, open-source, non-relational database from Google, is -now used to store transaction and block indices. LevelDB works much better -on machines with slow I/O and is faster in general. Berkeley DB is now only -used for the wallet.dat file (public and private wallet keys and transactions -relevant to you). - -Pieter Wuille implemented many optimizations to the way transactions are -verified, so a running, synchronized node uses much less memory and does -much less I/O. He also implemented parallel signature checking, so if you -have a multi-CPU machine all CPUs will be used to verify transactions. - -New Features ------------- - -"Bloom filter" support in the network protocol for sending only relevant transactions to -lightweight clients. - -contrib/verifysfbinaries is a shell-script to verify that the binary downloads -at sourceforge have not been tampered with. If you are able, you can help make -everybody's downloads more secure by running this occasionally to check PGP -signatures against download file checksums. - -contrib/spendfrom is a python-language command-line utility that demonstrates -how to use the "raw transactions" JSON-RPC api to send coins received from particular -addresses (also known as "coin control"). - -New/changed settings (command-line or bitcoin.conf file) --------------------------------------------------------- - -dbcache : now controls LevelDB memory usage. Running with (for example) -dbcache=1000 -will use a gigabyte of memory and might make the initial blockchain download faster. - -par : controls how many threads to use to validate transactions. Defaults to the number -of CPUs on your machine, use -par=1 to limit to a single CPU. - -txindex : maintains an extra index of old, spent transaction ids so they will be found -by the getrawtransaction JSON-RPC method. Can only be set when the database is -initialized. - -reindex : rebuild block and transaction indices from the downloaded block data. - -New JSON-RPC API Features -------------------------- - -lockunspent / listlockunspent allow locking transaction outputs for a period of time so -they will not be spent by other processes that might be accessing the same wallet. - -addnode / getaddednodeinfo methods, to connect to specific peers without restarting. - -importprivkey now takes an optional boolean parameter (default true) to control whether -or not to rescan the blockchain for transactions after importing a new private key. - -gettxout retrieves a single transaction output from the current set of unspent outputs. -Optionally, the mempool transactions are taken into account. - -gettxoutsetinfo calculates statistics about the current set of unspent outputs. - -Important Bug Fixes -------------------- - -Privacy leak: the position of the "change" output in most transactions was not being -properly randomized, making network analysis of the transaction graph to identify -users' wallets easier. - -Zero-confirmation transaction vulnerability: accepting zero-confirmation transactions -(transactions that have not yet been included in a block) from somebody you do not -trust is still not recommended, because there will always be ways for attackers to -double-spend zero-confirmation transactions. However, this release includes a bug -fix that makes it a little bit more difficult for attackers to double-spend a -certain type ("lockTime in the future") of zero-confirmation transaction. - -Dependency Changes +Fee Policy changes ------------------ -Qt 4.8.3 (compiling against older versions of Qt 4 should continue to work) +The default fee for low-priority transactions is lowered from 0.0005 BTC +(for each 1,000 bytes in the transaction; an average transaction is +about 500 bytes) to 0.0001 BTC. + +Payments (transaction outputs) of 0.543 times the minimum relay fee +(0.00005430 BTC) are now considered 'non-standard', because storing them +costs the network more than they are worth and spending them will usually +cost their owner more in transaction fees than they are worth. + +Non-standard transactions are not relayed across the network, are not included +in blocks by most miners, and will not show up in your wallet until they are +included in a block. + +The default fee policy can be overridden using the -mintxfee and -minrelaytxfee +command-line options, but note that we intend to replace the hard-coded fees +with code that automatically calculates and suggests appropriate fees in the +0.9 release and note that if you set a fee policy significantly different from +the rest of the network your transactions may never confirm. + +Bitcoin-Qt changes +------------------ + +* New icon and splash screen +* Improve reporting of synchronization process +* Remove hardcoded fee recommendations +* Improve metadata of executable on MacOSX and Windows +* Move export button to individual tabs instead of toolbar +* Add "send coins" command to context menu in address book +* Add "copy txid" command to copy transaction IDs from transaction overview +* Save & restore window size and position when showing & hiding window +* New translations: Arabic (ar), Bosnian (bs), Catalan (ca), Welsh (cy), + Esperanto (eo), Interlingua (la), Latvian (lv) and many improvements + to current translations + +MacOSX: +* OSX support for click-to-pay (bitcoin:) links +* Fix GUI disappearing problem on MacOSX (issue #1522) + +Linux/Unix: +* Copy addresses to middle-mouse-button clipboard + + +Command-line options +-------------------- + +* -walletnotify will call a command on receiving transactions that affect the wallet. +* -alertnotify will call a command on receiving an alert from the network. +* -par now takes a negative number, to leave a certain amount of cores free. + +JSON-RPC API changes +-------------------- + +* listunspent now lists account and address infromation. +* getinfo now also returns the time adjustment estimated from your peers. +* getpeerinfo now returns bytessent, bytesrecv and syncnode. +* gettxoutsetinfo returns statistics about the unspent transaction output database. +* gettxout returns information about a specific unspent transaction output. + + +Networking changes +------------------ + +* Significant changes to the networking code, reducing latency and memory consumption. +* Avoid initial block download stalling. +* Remove IRC seeding support. +* Performance tweaks. +* Added testnet DNS seeds. + +Wallet compatibility/rescuing +----------------------------- + +* Cases where wallets cannot be opened in another version/installation should be reduced. +* -salvagewallet now works for encrypted wallets. From 5b5d399593adbdf8b9b4fb49ef39d51d4eac03cd Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Fri, 10 May 2013 09:50:33 -0400 Subject: [PATCH 34/69] Update version numbers for 0.8.2rc1 release --- bitcoin-qt.pro | 2 +- contrib/verifysfbinaries/verify.sh | 2 +- doc/README | 2 +- doc/README_windows.txt | 15 +++++---------- share/setup.nsi | 6 +++--- src/clientversion.h | 4 ++-- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 07eadb5db..a217836df 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -1,7 +1,7 @@ TEMPLATE = app TARGET = bitcoin-qt macx:TARGET = "Bitcoin-Qt" -VERSION = 0.8.0 +VERSION = 0.8.2 INCLUDEPATH += src src/json src/qt QT += network DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh index b109cd3ed..768be86bd 100755 --- a/contrib/verifysfbinaries/verify.sh +++ b/contrib/verifysfbinaries/verify.sh @@ -18,7 +18,7 @@ WORKINGDIR="/tmp/bitcoin" TMPFILE="hashes.tmp" #this URL is used if a version number is not specified as an argument to the script -SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.8.1/SHA256SUMS.asc" +SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.8.2/SHA256SUMS.asc" SIGNATUREFILENAME="SHA256SUMS.asc" RCSUBDIR="test/" diff --git a/doc/README b/doc/README index dfcb25938..ecd9c6036 100644 --- a/doc/README +++ b/doc/README @@ -1,4 +1,4 @@ -Bitcoin 0.8.0 BETA +Bitcoin 0.8.2 BETA Copyright (c) 2009-2013 Bitcoin Developers Distributed under the MIT/X11 software license, see the accompanying diff --git a/doc/README_windows.txt b/doc/README_windows.txt index 9e7c0836b..b26fab3be 100644 --- a/doc/README_windows.txt +++ b/doc/README_windows.txt @@ -1,4 +1,4 @@ -Bitcoin 0.8.0 BETA +Bitcoin 0.8.2 BETA Copyright (c) 2009-2013 Bitcoin Developers Distributed under the MIT/X11 software license, see the accompanying @@ -20,15 +20,10 @@ Setup ----- Unpack the files into a directory and run bitcoin-qt.exe. -If you have Microsoft Security Essentials, you need to add bitcoin.exe to its -"Excluded processes" list. Microsoft Security Essentials->Settings tab, -select Excluded processes, press Add, select bitcoin.exe, OK, Save changes. - -The software automatically finds other nodes to connect to. You can -enable Universal Plug and Play using a menu entry or set your firewall -to forward port 8333 (TCP) to your computer so you can receive -incoming connections. Bitcoin works without incoming connections, -but allowing incoming connections helps the Bitcoin network. +Bitcoin-Qt is the original Bitcoin client and it builds the backbone of the network. +However, it downloads and stores the entire history of Bitcoin transactions; +depending on the speed of your computer and network connection, the synchronization +process can take anywhere from a few hours to a day or more. See the bitcoin wiki at: https://en.bitcoin.it/wiki/Main_Page diff --git a/share/setup.nsi b/share/setup.nsi index 307db6f62..4a7b0b1da 100644 --- a/share/setup.nsi +++ b/share/setup.nsi @@ -5,7 +5,7 @@ SetCompressor /SOLID lzma # General Symbol Definitions !define REGKEY "SOFTWARE\$(^Name)" -!define VERSION 0.8.0 +!define VERSION 0.8.2 !define COMPANY "Bitcoin project" !define URL http://www.bitcoin.org/ @@ -45,13 +45,13 @@ Var StartMenuGroup !insertmacro MUI_LANGUAGE English # Installer attributes -OutFile bitcoin-0.8.0-win32-setup.exe +OutFile bitcoin-0.8.2-win32-setup.exe InstallDir $PROGRAMFILES\Bitcoin CRCCheck on XPStyle on BrandingText " " ShowInstDetails show -VIProductVersion 0.8.0.0 +VIProductVersion 0.8.2.0 VIAddVersionKey ProductName Bitcoin VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey CompanyName "${COMPANY}" diff --git a/src/clientversion.h b/src/clientversion.h index 635641bd2..d6ca03a72 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -8,8 +8,8 @@ // These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 8 -#define CLIENT_VERSION_REVISION 1 -#define CLIENT_VERSION_BUILD 99 +#define CLIENT_VERSION_REVISION 2 +#define CLIENT_VERSION_BUILD 0 // Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE false From 5d274c9927f01c590f187bbbc670a92e441c53b7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 12 May 2013 12:03:32 +0200 Subject: [PATCH 35/69] Check for correct genesis At startup, check that the expected genesis is loaded. This should prevent cases where accidentally a datadir from the wrong network is loaded (testnet vs mainnet, e.g.). --- src/init.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index d619cb412..1e2ffe48e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -862,6 +862,11 @@ bool AppInit2(boost::thread_group& threadGroup) break; } + // If the loaded chain has a wrong genesis, bail out immediately + // (we're likely using a testnet datadir, or the other way around). + if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL) + return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); + // Initialize the block index (no-op if non-empty database was already loaded) if (!InitBlockIndex()) { strLoadError = _("Error initializing block database"); From 0fe8010a10bafd67f9131b2da034fb9cd7fc5024 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 12 May 2013 15:50:22 +0200 Subject: [PATCH 36/69] Make FindBlockByHeight constant-time. Remove the pnext pointer in CBlockIndex, and replace it with a vBlockIndexByHeight vector (no effect on memory usage). pnext can now be replaced by vBlockIndexByHeight[nHeight+1], but FindBlockByHeight becomes constant-time. This also means the entire mapBlockIndex structure and the block index entries in it become purely blocktree-related data, and independent from the currently active chain, potentially allowing them to be protected by separate mutexes in the future. --- .../test-patches/bitcoind-comparison.patch | 2 +- src/main.cpp | 54 +++++++------------ src/main.h | 24 ++++----- src/rpcblockchain.cpp | 5 +- src/wallet.cpp | 2 +- 5 files changed, 36 insertions(+), 51 deletions(-) diff --git a/contrib/test-patches/bitcoind-comparison.patch b/contrib/test-patches/bitcoind-comparison.patch index 7464349b3..f82b102e2 100644 --- a/contrib/test-patches/bitcoind-comparison.patch +++ b/contrib/test-patches/bitcoind-comparison.patch @@ -3,9 +3,9 @@ index 04a8618..519429a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,8 +31,8 @@ CTxMemPool mempool; - unsigned int nTransactionsUpdated = 0; map mapBlockIndex; + std::vector vBlockIndexByHeight; -uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); -static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); +uint256 hashGenesisBlock("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"); diff --git a/src/main.cpp b/src/main.cpp index e2bed5278..5fa35f011 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,6 +31,7 @@ CTxMemPool mempool; unsigned int nTransactionsUpdated = 0; map mapBlockIndex; +std::vector vBlockIndexByHeight; uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); CBlockIndex* pindexGenesisBlock = NULL; @@ -1036,19 +1037,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock static CBlockIndex* pblockindexFBBHLast; CBlockIndex* FindBlockByHeight(int nHeight) { - CBlockIndex *pblockindex; - if (nHeight < nBestHeight / 2) - pblockindex = pindexGenesisBlock; - else - pblockindex = pindexBest; - if (pblockindexFBBHLast && abs(nHeight - pblockindex->nHeight) > abs(nHeight - pblockindexFBBHLast->nHeight)) - pblockindex = pblockindexFBBHLast; - while (pblockindex->nHeight > nHeight) - pblockindex = pblockindex->pprev; - while (pblockindex->nHeight < nHeight) - pblockindex = pblockindex->pnext; - pblockindexFBBHLast = pblockindex; - return pblockindex; + if (nHeight >= (int)vBlockIndexByHeight.size()) + return NULL; + return vBlockIndexByHeight[nHeight]; } bool CBlock::ReadFromDisk(const CBlockIndex* pindex) @@ -1231,7 +1222,7 @@ void static InvalidBlockFound(CBlockIndex *pindex) { pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex)); setBlockIndexValid.erase(pindex); InvalidChainFound(pindex); - if (pindex->pnext) { + if (pindex->GetNextInMainChain()) { CValidationState stateDummy; ConnectBestBlock(stateDummy); // reorganise away from the failed block } @@ -1271,7 +1262,7 @@ bool ConnectBestBlock(CValidationState &state) { if (pindexBest == NULL || pindexTest->nChainWork > pindexBest->nChainWork) vAttach.push_back(pindexTest); - if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) { + if (pindexTest->pprev == NULL || pindexTest->GetNextInMainChain()) { reverse(vAttach.begin(), vAttach.end()); BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) { boost::this_thread::interruption_point(); @@ -1849,15 +1840,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) // At this point, all changes have been done to the database. // Proceed by updating the memory structures. - // Disconnect shorter branch - BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) - if (pindex->pprev) - pindex->pprev->pnext = NULL; - - // Connect longer branch + // Register new best chain + vBlockIndexByHeight.resize(pindexNew->nHeight + 1); BOOST_FOREACH(CBlockIndex* pindex, vConnect) - if (pindex->pprev) - pindex->pprev->pnext = pindex; + vBlockIndexByHeight[pindex->nHeight] = pindex; // Resurrect memory transactions that were in the disconnected branch BOOST_FOREACH(CTransaction& tx, vResurrect) { @@ -2609,12 +2595,12 @@ bool static LoadBlockIndexDB() nBestHeight = pindexBest->nHeight; nBestChainWork = pindexBest->nChainWork; - // set 'next' pointers in best chain + // register best chain CBlockIndex *pindex = pindexBest; - while(pindex != NULL && pindex->pprev != NULL) { - CBlockIndex *pindexPrev = pindex->pprev; - pindexPrev->pnext = pindex; - pindex = pindexPrev; + vBlockIndexByHeight.resize(pindexBest->nHeight + 1); + while(pindex != NULL) { + vBlockIndexByHeight[pindex->nHeight] = pindex; + pindex = pindex->pprev; } printf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n", hashBestChain.ToString().c_str(), nBestHeight, @@ -2683,7 +2669,7 @@ bool VerifyDB() { CBlockIndex *pindex = pindexState; while (pindex != pindexBest) { boost::this_thread::interruption_point(); - pindex = pindex->pnext; + pindex = pindex->GetNextInMainChain(); CBlock block; if (!block.ReadFromDisk(pindex)) return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); @@ -2859,7 +2845,7 @@ void PrintBlockTree() vector& vNext = mapNext[pindex]; for (unsigned int i = 0; i < vNext.size(); i++) { - if (vNext[i]->pnext) + if (vNext[i]->GetNextInMainChain()) { swap(vNext[0], vNext[i]); break; @@ -3440,10 +3426,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Send the rest of the chain if (pindex) - pindex = pindex->pnext; + pindex = pindex->GetNextInMainChain(); int nLimit = 500; printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit); - for (; pindex; pindex = pindex->pnext) + for (; pindex; pindex = pindex->GetNextInMainChain()) { if (pindex->GetBlockHash() == hashStop) { @@ -3483,14 +3469,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Find the last block the caller has in the main chain pindex = locator.GetBlockIndex(); if (pindex) - pindex = pindex->pnext; + pindex = pindex->GetNextInMainChain(); } // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end vector vHeaders; int nLimit = 2000; printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str()); - for (; pindex; pindex = pindex->pnext) + for (; pindex; pindex = pindex->GetNextInMainChain()) { vHeaders.push_back(pindex->GetBlockHeader()); if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) diff --git a/src/main.h b/src/main.h index cba8421c8..020f23548 100644 --- a/src/main.h +++ b/src/main.h @@ -69,6 +69,7 @@ extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern std::map mapBlockIndex; +extern std::vector vBlockIndexByHeight; extern std::set setBlockIndexValid; extern uint256 hashGenesisBlock; extern CBlockIndex* pindexGenesisBlock; @@ -1589,10 +1590,8 @@ enum BlockStatus { /** The block chain is a tree shaped structure starting with the * genesis block at the root, with each block potentially having multiple - * candidates to be the next block. pprev and pnext link a path through the - * main/longest chain. A blockindex may have multiple pprev pointing back - * to it, but pnext will only point forward to the longest branch, or will - * be null if the block is not part of the longest chain. + * candidates to be the next block. A blockindex may have multiple pprev pointing + * to it, but at most one of them can be part of the currently active branch. */ class CBlockIndex { @@ -1603,9 +1602,6 @@ public: // pointer to the index of the predecessor of this block CBlockIndex* pprev; - // (memory only) pointer to the index of the *active* successor of this block - CBlockIndex* pnext; - // height of the entry in the chain. The genesis block has height 0 int nHeight; @@ -1643,7 +1639,6 @@ public: { phashBlock = NULL; pprev = NULL; - pnext = NULL; nHeight = 0; nFile = 0; nDataPos = 0; @@ -1664,7 +1659,6 @@ public: { phashBlock = NULL; pprev = NULL; - pnext = NULL; nHeight = 0; nFile = 0; nDataPos = 0; @@ -1733,7 +1727,11 @@ public: bool IsInMainChain() const { - return (pnext || this == pindexBest); + return nHeight < (int)vBlockIndexByHeight.size() && vBlockIndexByHeight[nHeight] == this; + } + + CBlockIndex *GetNextInMainChain() const { + return nHeight+1 >= (int)vBlockIndexByHeight.size() ? NULL : vBlockIndexByHeight[nHeight+1]; } bool CheckIndex() const @@ -1762,9 +1760,9 @@ public: const CBlockIndex* pindex = this; for (int i = 0; i < nMedianTimeSpan/2; i++) { - if (!pindex->pnext) + if (!pindex->GetNextInMainChain()) return GetBlockTime(); - pindex = pindex->pnext; + pindex = pindex->GetNextInMainChain(); } return pindex->GetMedianTimePast(); } @@ -1779,7 +1777,7 @@ public: std::string ToString() const { return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, pnext, nHeight, + pprev, GetNextInMainChain(), nHeight, hashMerkleRoot.ToString().c_str(), GetBlockHash().ToString().c_str()); } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 11af1abf5..b1b0c1ac1 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -65,8 +65,9 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - if (blockindex->pnext) - result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); + CBlockIndex *pnext = blockindex->GetNextInMainChain(); + if (pnext) + result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; } diff --git a/src/wallet.cpp b/src/wallet.cpp index c70ea20e8..1cc248323 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -780,7 +780,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) ret++; } - pindex = pindex->pnext; + pindex = pindex->GetNextInMainChain(); } } return ret; From 8ae290d266326893a19c31e67258f6fbed6dbd37 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Mon, 13 May 2013 10:53:53 -0400 Subject: [PATCH 37/69] Set CLIENT_VERSION_IS_RELEASE, bump build to 0.8.2.1 --- share/setup.nsi | 2 +- src/clientversion.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/share/setup.nsi b/share/setup.nsi index 4a7b0b1da..3715b4620 100644 --- a/share/setup.nsi +++ b/share/setup.nsi @@ -51,7 +51,7 @@ CRCCheck on XPStyle on BrandingText " " ShowInstDetails show -VIProductVersion 0.8.2.0 +VIProductVersion 0.8.2.1 VIAddVersionKey ProductName Bitcoin VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey CompanyName "${COMPANY}" diff --git a/src/clientversion.h b/src/clientversion.h index d6ca03a72..aabab4c72 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -9,10 +9,10 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 8 #define CLIENT_VERSION_REVISION 2 -#define CLIENT_VERSION_BUILD 0 +#define CLIENT_VERSION_BUILD 1 // Set to true for release, false for prerelease or test build -#define CLIENT_VERSION_IS_RELEASE false +#define CLIENT_VERSION_IS_RELEASE true // Copyright year (2009-this) // Todo: update this when changing our copyright comments in the source From d0d4080013d507aed625043dd9b422623aab015d Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sun, 12 May 2013 20:24:53 +0200 Subject: [PATCH 38/69] new icons for linux, etc. - new xpm resources for different linux window managers - new png files for autoresizing on different linux window managers - favicon with new logo - window .ico with new logo - updated debian package script - updated changelog --- contrib/debian/bitcoin-qt.desktop | 2 +- contrib/debian/bitcoin-qt.install | 3 +- contrib/debian/changelog | 6 + share/pixmaps/bitcoin.ico | Bin 306398 -> 353118 bytes share/pixmaps/bitcoin128.png | Bin 0 -> 12930 bytes share/pixmaps/bitcoin128.xpm | 384 ++++++++++++++++++++++++ share/pixmaps/bitcoin16.png | Bin 0 -> 1838 bytes share/pixmaps/bitcoin16.xpm | 181 ++++++++++++ share/pixmaps/bitcoin256.png | Bin 0 -> 32814 bytes share/pixmaps/bitcoin256.xpm | 465 ++++++++++++++++++++++++++++++ share/pixmaps/bitcoin32.png | Bin 0 -> 3038 bytes share/pixmaps/bitcoin32.xpm | 364 +++++++++-------------- share/pixmaps/bitcoin64.png | Bin 0 -> 6026 bytes share/pixmaps/bitcoin64.xpm | 242 ++++++++++++++++ share/pixmaps/bitcoin80.xpm | 292 ------------------- share/pixmaps/favicon.ico | Bin 2550 -> 1150 bytes 16 files changed, 1417 insertions(+), 522 deletions(-) create mode 100644 share/pixmaps/bitcoin128.png create mode 100644 share/pixmaps/bitcoin128.xpm create mode 100644 share/pixmaps/bitcoin16.png create mode 100644 share/pixmaps/bitcoin16.xpm create mode 100644 share/pixmaps/bitcoin256.png create mode 100644 share/pixmaps/bitcoin256.xpm create mode 100644 share/pixmaps/bitcoin32.png create mode 100644 share/pixmaps/bitcoin64.png create mode 100644 share/pixmaps/bitcoin64.xpm delete mode 100644 share/pixmaps/bitcoin80.xpm diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop index 7cb00a2c8..5d6f781e4 100644 --- a/contrib/debian/bitcoin-qt.desktop +++ b/contrib/debian/bitcoin-qt.desktop @@ -7,6 +7,6 @@ Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi Exec=/usr/bin/bitcoin-qt Terminal=false Type=Application -Icon=/usr/share/pixmaps/bitcoin80.xpm +Icon=/usr/share/pixmaps/bitcoin128.png MimeType=x-scheme-handler/bitcoin; Categories=Office; diff --git a/contrib/debian/bitcoin-qt.install b/contrib/debian/bitcoin-qt.install index ba407134e..59cacb0e9 100644 --- a/contrib/debian/bitcoin-qt.install +++ b/contrib/debian/bitcoin-qt.install @@ -1,5 +1,6 @@ bitcoin-qt usr/bin share/pixmaps/bitcoin32.xpm usr/share/pixmaps -share/pixmaps/bitcoin80.xpm usr/share/pixmaps +share/pixmaps/bitcoin16.xpm usr/share/pixmaps +share/pixmaps/bitcoin128.png usr/share/pixmaps debian/bitcoin-qt.desktop usr/share/applications debian/bitcoin-qt.protocol usr/share/kde4/services/ diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 4388e7175..e600e4670 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +bitcoin (0.8.1-natty3) natty; urgency=low + + * New pixmaps + + -- Jonas Schnelli Mon, 13 May 2013 16:14:00 +0100 + bitcoin (0.8.1-natty2) natty; urgency=low * Remove dumb broken launcher script diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico index 61926807cc8d324562251501b9dfcf8894bb50e0..48a9822a46abd9da41d10f44dae5c34ba405afcc 100644 GIT binary patch literal 353118 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 %`k;G1CUE=#-w*I|gTelQ&1ujd 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 diff --git a/share/pixmaps/bitcoin128.png b/share/pixmaps/bitcoin128.png new file mode 100644 index 0000000000000000000000000000000000000000..04b56cf2a0324e9a91729761e420840355e4a0f9 GIT binary patch literal 12930 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 c #8F6125", +", c #956727", +"< c #916B2E", +"1 c #996B2C", +"2 c #B47B23", +"3 c #BD7C20", +"4 c #A17330", +"5 c #AB7D3B", +"6 c #C17F20", +"7 c #B9831F", +"8 c #BB842B", +"9 c #BD8533", +"0 c #B68F3D", +"q c #BE8C3B", +"w c #C4801F", +"e c #FE8C03", +"r c #F38A0F", +"t c #FD8E0A", +"y c #FF910C", +"u c #F78F13", +"i c #F98F10", +"p c #F79016", +"a c #FE9314", +"s c #F6931E", +"d c #FD961B", +"f c #FE991E", +"g c #C58421", +"h c #CD8621", +"j c #C78B21", +"k c #CC8B23", +"l c #C2852B", +"z c #C08B2D", +"x c #D28722", +"c c #D38B25", +"v c #DB8E22", +"b c #D28E2C", +"n c #D49323", +"m c #DC9224", +"M c #DC9B25", +"N c #D4922D", +"B c #DF972A", +"V c #DF982E", +"C c #C18D33", +"Z c #C58E38", +"A c #CB9332", +"S c #C2933C", +"D c #CD9339", +"F c #CC9938", +"G c #D19733", +"H c #DA9230", +"J c #D59935", +"K c #DC9C33", +"L c #DC9E3B", +"P c #E49124", +"I c #EA9426", +"U c #E09D26", +"Y c #EC972B", +"T c #F79625", +"R c #F99524", +"E c #F69A26", +"W c #F89825", +"Q c #F2972B", +"! c #F59A2C", +"~ c #F89B2B", +"^ c #E79D33", +"/ c #EF9D31", +"( c #E19F3A", +") c #EF9D3A", +"_ c #F49C33", +"` c #F99E32", +"' c #F49F39", +"] c #D6A13E", +"[ c #DAA33B", +"{ c #E3A127", +"} c #E7A328", +"| c #EDA32C", +" . c #EDA829", +".. c #FFA325", +"X. c #FFAB25", +"o. c #F3A42B", +"O. c #FFA429", +"+. c #F4A929", +"@. c #FFAC2A", +"#. c #FFB227", +"$. c #FFB32C", +"%. c #FFBA2D", +"&. c #EEA830", +"*. c #F7A334", +"=. c #FAA036", +"-. c #FCAB34", +";. c #F4A13C", +":. c #F9A33B", +">. c #F4A83B", +",. c #FFA83F", +"<. c #FDB432", +"1. c #FFBB33", +"2. c #FFB73A", +"3. c #FDB93E", +"4. c #FFC12F", +"5. c #FFC432", +"6. c #FFC338", +"7. c #D2A043", +"8. c #D8A140", +"9. c #EEA144", +"0. c #E2A840", +"q. c #EDA34B", +"w. c #F4A444", +"e. c #F9A642", +"r. c #FBA945", +"t. c #F3A64B", +"y. c #F4A84E", +"u. c #FBAB4B", +"i. c #EEB041", +"p. c #FABA44", +"a. c #ECA653", +"s. c #EEAC5D", +"d. c #F3AA53", +"f. c #FAAE53", +"g. c #F2AD5A", +"h. c #FBB056", +"j. c #F6B15E", +"k. c #FBB25B", +"l. c #DDAF79", +"z. c #E3A962", +"x. c #EBAE63", +"c. c #E4AC68", +"v. c #EAAF69", +"b. c #EEB065", +"n. c #E7B06C", +"m. c #EEB36B", +"M. c #F5B263", +"N. c #FBB461", +"B. c #E6B274", +"V. c #ECB574", +"C. c #E7B57B", +"Z. c #EAB77C", +"A. c #ECB97C", +"S. c #F2B770", +"D. c #F0BB7A", +"F. c #DBB485", +"G. c #DFB888", +"H. c #E4B984", +"J. c #EDBD82", +"K. c #E5BC8B", +"L. c #EABE8A", +"P. c #F0BE82", +"I. c #E0BF96", +"U. c #EDC089", +"Y. c #F0C28B", +"T. c #E5C194", +"R. c #E9C191", +"E. c #E4C39C", +"W. c #EBC699", +"Q. c #EBC99F", +"!. c #DFC3A0", +"~. c #DDCAAF", +"^. c #CFC7BD", +"/. c #D2CBB6", +"(. c #DBC8B1", +"). c #DBCDBB", +"_. c #E2C6A4", +"`. c #E6C8A5", +"'. c #EACBA5", +"]. c #E1C7A8", +"[. c #E3CBAD", +"{. c #EACCAA", +"}. c #EED1AC", +"|. c #E1CDB3", +" X c #E3CFB8", +".X c #E6D1B6", +"XX c #EBD2B3", +"oX c #E3D1BB", +"OX c #EAD6BB", +"+X c #EBD8BF", +"@X c #D3CDC2", +"#X c #D8CDC2", +"$X c #D0CECA", +"%X c #DDD3C4", +"&X c #D3D2CC", +"*X c #DDD5CB", +"=X c #CCD3D5", +"-X c #C9D7DF", +";X c #D2D4D6", +":X c #DEDAD4", +">X c #DDDCDB", +",X c #E2D4C2", +".N b b b b N >.( C > HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX4 L _ *.@.<.$.X.X...X.X.X.X.X.X...X.@.$.<.@.*./ G , HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX< L -.@.$.X...R R R T T T T W W W W W W T T T T R R W ..X.$.@.*.J HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD -.%.X.W R T T W W W W W W W W W W W W W W W W W W W W W W T T R W X.%.+.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS -.$.X.R T T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T T R X.$.-.C HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXF <.@.f R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R W #.<.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX[ <.X.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R X.$.K HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0.$...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W W W W W W W T R ..%.G HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS 1...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ E W W W W W W W W W T R X.1.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.d T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ E W W W W W W W W W W T R @.2.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX7.5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W T W %.z HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.s T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W T R $.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1...R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W R ..1.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0 5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T W 5.8 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX8.$.s W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W T R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.#.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R $.&.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ E ~ W R ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W R @.| HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX] #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ! s e t d ~ ` ` ` ` ` ` =.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXq %.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W E ~ ~ ~ ~ y l.=XI.x.) p a =.` ` =.=.=.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %.2 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5 5.d W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t (.jXVXNXuX@XF.W ` =.:.` W =.:.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ R Q eXDXSXSXDXgX#Xa ` =.=.;.q.W a a R ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3...T W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ` a a.NXSXGXGXAXNXV.a :.:.f c.tX*XE.n.9.R ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T @.@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t H.VXSXGXGXDXmXy.f :.:.a I.hXBXCXNXiX^.' W ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.g HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5.d W W W W W W W W W W W W W W W W W W W W W W W W W E ~ W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` i |.CXGXGXGXCX3X~ ` :.:.R %XCXSXGXAXNX>XW ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX2.W T W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ s t e a W ~ ` ` ` ` ` ` W ! eXFXGXGXSXVX[.d :.:.~ w.uXFXGXGXSXVXW.a ` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T ..@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX9 $.R W W W W W W W W W W W W W W W W W W W W W W E W ~ ~ ~ y F./.B.9.T t t a ~ =.` =.a a.hXDXGXGXSXNXA.d :.e.R v.NXSXGXGXSXNXm.a =.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.= HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX6.d W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ W i &XjXNXfX:X].B.q.T t a d e K.VXSXGXGXDXaXd.W e.e.d E.VXSXGXGXDXvXw.W =.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHXK X.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ a ) uXDXSXFXFXCXNXfX:X_.B.q.r .XFXGXGXGXCX3X=.=.e.,.~ %XCXGXGXGXCX1XW ` =.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T $.m HXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHXHX5.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t x.NXSXGXGXGXSXSXDXFXCXNXmX8XcXSXGXGXGXCXW.e :.e.=.t.uXFXGXGXSXVXE.d :.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHX^ X.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t T.VXSXGXGXGXGXGXGXGXSXSXFXGXGXGXGXGXGXFX}.9.' W e v.VXSXGXGXSXNXm.d :.=.=.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W T @.P HXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ s ;XNXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXNX>X|.V.XXFXGXGXGXFXbXy.~ :.:.=.=.` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHXH X.T W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` R ' $XsXNXVXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXCXCXFXSXGXGXGXCXOXa :.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T $.c HXHXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ~ t.V.`.5XVXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXSXCX{.e.P.'.2XvXNXBXDXSXGXGXGXGXGXGXGXGXGXSXDXjX~.y W =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX: 1.R W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.~ s.fXDXGXGXGXGXGXGXGXSXNXD.f =.=.,.M.L.oXaXVXDXSXGXGXGXGXGXGXGXGXGXAXVX(.t ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %. HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXl #.T W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.:.:.:.:.:.:.:.:.:.e.e.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXzXg.r.f.f.f.r.=.=.g.`.fXBXAXGXGXGXGXGXGXGXGXGXAXjXH.t =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T $.6 HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX~ ..W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX1X,.f.f.f.f.h.h.f.,.~ d.3XVXAXGXGXGXGXGXGXGXGXGXDXsX' f ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W ..~ HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX$.R W W W W W E ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.,.w.>XFXGXGXGXGXGXGXGXSXNX`.=.f.h.h.h.h.f.f.f.f.=.~ ,XVXSXGXGXGXGXGXGXGXGXSXVXT.y ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R $.HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXX %.T W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.e.r.r.r.u.=.x.fXDXGXGXGXGXGXGXGXSXmXA.,.h.h.h.k.k.h.f.f.f.f.:.~ 5XFXGXGXGXGXGXGXGXGXGXCX:XW ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W T $.. HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX8 $.T W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.r.r.u.u.~ K.NXSXGXGXGXGXGXGXGXDXzXj.r.k.k.k.k.k.h.f.f.f.f.f.W V.VXSXGXGXGXGXGXGXGXGXDXuXw.f ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W T $.3 HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXY ..W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.e.e.e.e.e.e.r.r.r.r.u.u.u.u.~ |.CXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.f.f.f.f.,.d.bXFXGXGXGXGXGXGXGXGXDXfXd.d =.` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W O.P HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXO.W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.e.r.r.r.r.r.r.u.u.u.u.r.w.>XFXGXGXGXGXGXGXGXSXNX'.,.k.k.k.k.k.k.k.h.h.f.f.f.e.y.kXFXGXGXGXGXGXGXGXGXDXfXg.d =.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W O.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX$.R W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.:.:.:.:.e.e.r.r.r.r.u.u.u.u.u.u.f.=.b.fXDXGXGXGXGXGXGXGXSXmXJ.r.k.k.k.k.k.k.k.h.h.f.f.f.:.s.mXFXGXGXGXGXGXGXGXGXDXpXy.R =.` ` ` ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX1.R W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXFXxXM.u.k.k.k.k.k.k.k.k.h.f.f.k.~ K.VXSXGXGXGXGXGXGXGXGXCX5X=.~ =.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHX+ $.T W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.f.f.=.|.CXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXGXFX9XA.b.u.r.r.u.u.h.h.h.u.r.O.w.:XCXSXGXGXGXGXGXGXGXGXSXhXL.a :.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.* HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXV X.T W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.,.b.fXFXGXGXGXGXGXGXGXGXSXFXVXpX*X[.R.V.M.g.d.d.g.b.T.pXCXSXGXGXGXGXGXGXGXGXGXDXpXe.~ :.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.; HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHX| O.T W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXmXuX>X3X3XyXmXVXFXSXGXGXGXGXGXGXGXGXGXAXhXE.d :.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.:.:.:.:.:.e.e.e.r.r.u.u.u.u.=.|.BXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXSXFXFXFXFXFXSXSXGXGXGXGXGXGXGXGXGXGXAXNX>X~ =.e.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.e.e.e.r.r.r.u.u.r.w.>XFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXZXNXeXe.~ e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.=.x.fXFXGXGXGXGXGXGXGXGXGXFXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXCXfXoX:.~ r.e.:.:.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.r.u.~ K.NXSXGXGXGXGXGXGXGXSXZX6XkXmXNXBXDXAXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGX0X'.S.~ =.u.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.r.r.u.~ |.CXGXGXGXGXGXGXGXGXFX4X,.k.D.Q.,XkXmXNXDXSXSXGXGXGXGXGXGXGXGXGXGXGXXFXGXGXGXGXGXGXGXSXVX{.,.f.u.r.u.N.J.{.5XNXBXAXSXGXGXGXGXGXGXGXGXGXFXMXH.W r.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXo.O.T W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.O.s.fXFXGXGXGXGXGXGXGXSXmXJ.r.N.N.N.N.h.r.r.f.J.1XhXBXAXGXGXGXGXGXGXGXGXSXDXjX!.W e.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W T @.g HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXB X.T W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.:.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXuXM.u.k.k.N.N.N.N.N.h.,.e.D.>XNXSXGXGXGXGXGXGXGXGXSXZXjXE.W r.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W T $.- HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXl @.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX2Xr.h.k.k.k.k.k.k.k.k.k.h.,.,.|.NXZXGXGXGXGXGXGXGXGXGXZXgXV.~ u.e.e.e.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.% HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHX@ $.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.:.' >XFXGXGXGXGXGXGXGXSXNX{.,.k.k.k.k.k.k.k.k.k.k.k.k.u.~ `.NXSXGXGXGXGXGXGXGXGXSXCX>X=.e.r.r.e.e.:.:.:.:.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.. HXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.~ s.fXFXGXGXGXGXGXGXGXSXNXJ.,.k.k.k.k.k.k.k.k.k.k.h.h.k.u.O.2XCXGXGXGXGXGXGXGXGXGXAXhXV.~ u.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` ~ :.:.:.:.e.f Z.VXSXGXGXGXGXGXGXGXDXzXM.r.k.k.k.k.k.k.k.h.h.h.h.f.f.k.=.V.NXSXGXGXGXGXGXGXGXGXSXVX`.W r.e.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W $.HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXO.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` =.~ Q a a W =.=.t XCXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.h.h.h.f.f.f.f.r.y.kXFXGXGXGXGXGXGXGXGXGXBX,X~ :.e.e.e.:.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W ~ ..HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXI O.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` a z.-X_.B.q.! u C.NXSXGXGXGXGXGXGXGXSXNX'.=.h.h.k.k.k.h.h.f.f.f.f.f.f.f.f.r.w.5XFXGXGXGXGXGXGXGXGXGXCX2X=.:.e.:.:.:.:.:.:.:.:.=.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W O.P HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ t ).jXVXNXaX2X1XBXDXSXGXGXGXGXGXGXGXSXmXA.:.h.h.h.h.h.f.f.f.f.f.f.f.f.f.f.,.d.vXFXGXGXGXGXGXGXGXGXGXCX1X` =.:.:.:.:.:.:.=.=.=.=.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W T $.; HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXo %.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ` y q.fXZXSXSXFXFXFXSXSXGXGXGXGXGXGXGXGXFXxXj.r.f.h.h.h.f.f.f.f.f.f.f.f.u.u.f.W B.NXSXGXGXGXGXGXGXGXGXSXBXoXW :.:.:.:.:.:.=.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W %. HXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ` e !.CXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX+Xd ,.f.h.h.h.f.f.f.f.f.f.u.u.u.f.,.T :XFXGXGXGXGXGXGXGXGXGXSXNXE.f :.:.:.:.:.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W R $.HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX~ ..W W W W W W W W W W W W W W W W W W W W E ~ ~ a _ aXFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX7XV.s.:.=.:.,.u.f.f.f.f.u.u.u.r.~ s ~.VXSXGXGXGXGXGXGXGXGXGXAXhXV.d :.:.=.=.=.=.=.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W O.E HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXg $.T W W W W W W W W W W W W W W W W W W W E ~ ~ e G.hXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXVXpX*X_.Z.x.t.:.` ~ ~ ~ ~ ~ ' x.*XVXSXGXGXGXGXGXGXGXGXGXGXDXuXw.W :.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W T $.; HXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHX %.R W W W W W W W W W W W W W W W W W W W W ~ d T qXgXBXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXaX>X,X[._.T.T.E.|.:XNXCXSXGXGXGXGXGXGXGXGXGXGXSXVX Xd =.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W R %.HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHX@.W W W W W W W W W W W W W W W W W W W W W ~ R ` s.H.oXkXNXNXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXDXFXCXCXBXVXVXBXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXAXhXm.a :.` =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXx @.T W W W W W W W W W W W W W W W W W W W W ~ ~ y t a _ g.L.oXkXhXVXCXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXGXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXBX:Xf ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W T $.h HXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ d a t a ' s.R.oXnXDXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXZXhXg.y =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ E ~ E W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHX", +"HXHXHXHXHXHXHXHXHXHXHXO.~ W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ` ` ~ W a a d ! lSgq#o&k{~IDGZmpZ2?Pi4p zEw{6oYeS(>?4$wWFmkjvJyui6xAXINFgeU2B#}fo8b|119HIEC&{zbJYT$Sz41rat z$!&-?g<_tdmPZnivK0a)s-eRs9lAk-k!T9V+sA;x%0z?!Vv%^YR!AK>*+d1@Dj_w3 zEdynk2uV-}q~S<-T990smZ;>bs6I;pZ-am&&>#d17&J**oxmWZzULK?bCZ}s1>UO= zi9+gxQ<1U|K!oB5z^1ckN)Uno4u=kTvN;@R3BUv)CIcjI4h`}YusH%I7x-{dNo%+& zP7o&c|6q$;38@JLfe9E4y&mlU8yV6Xft9i0{efNU>^5pxm*enQ=F#Y%vkSF5v*?dni zi_c|GVx?Lg0c(}Wq+K;>_XC#qS*$>WBQSyDauiLPtbmXNlt6U}CIm?XJm#@o2ThV-Gqx;IL;Mufx^ zN|tRWcKdCzw_}tn-eT!!-goxf8w$|ha8)5*KWz6nIH6=%aqWynPHW!c)(e}Vl3dQ= z>0Fl?3C6uNP2M{FN!?I;(X(zESde)_-!XDY->94B*q=?YEjBkSuYtynX1|t?J+7~F z>PUOE**a7+>R40sMz0!QsmvPuX>_g8O#kS7vy;7Hv*Z40Sy#ioUI}Yk=dG`_yZk(a z2in}mQtN-XnusLB@7(q%XVge92Lnx30;svG~fUID1dg zozch9($62tadY!29u>gs#DU_xKv8?9${C9Bndx!J8KXD8dC^l8%v&>e;~alZ=%qnF>d2?-N*oC^1a6 zEBR&f!`kw|yKABf`_d1ztEQ$ox>-rX&d+0PRSi4uXJ2l9+Vh3mEc2mTThsb=_oozS zwr|lrSsj0{J0>8m(m6OuQ26-hns~Um?~EBY5OR_Cufs0-rj2{bk6FH~wRET$H}i_5 zY;QJ3X;&>>deOML>&wog4mUQ1OwW(jU$48QoA~duI`=NE|4U5B?Zm z7rr{zMGh_u4m1m0CEgQ%q@CXF)#Ol4VWxK7qtCy->@f3}9gB0_T~}9CjhBhaz8?t1 zgsZmvwb8jwbGkfwoBoYkWDc`%!JXoQOslf;tiu_FH3Lmm8!w#7nO(my+d6Lq$0P4p z=f9d?X|SO-SYPTkbN8}K9E(3r8@Jy6^?DDee*RlLNi}$!ZFGOo(KGsFth&pgIpc9e zu^*n%KCS$rHr2MRJUif0Ooqb<;31RdHSImK@8Hhw0z;kihpKN3{&uWXcpzxltd$q* zyJ$xzT0Y!Eu#BVWJAVIprC0cr7v$%rrlWCK{d!)@*b3X(y$#6?ofjf}+Kbv!c;__x zPPu$pGN)AL6y9*&<)+PjmeL$o_=aw!JtO2J(Bh3-Hx5nMb9G6 grT(gLQoNn5px~Exztv%T(oKIbsU%2T?Wf528-YR6%K!iX literal 0 HcmV?d00001 diff --git a/share/pixmaps/bitcoin16.xpm b/share/pixmaps/bitcoin16.xpm new file mode 100644 index 000000000..40a0624ac --- /dev/null +++ b/share/pixmaps/bitcoin16.xpm @@ -0,0 +1,181 @@ +/* XPM */ +static char *bitcoin__[] = { +/* columns rows colors chars-per-pixel */ +"16 16 159 2", +" c #CA7C1E", +". c #CB7D1E", +"X c #D1811E", +"o c #D0801F", +"O c #D1801F", +"+ c #D3821F", +"@ c #D7831F", +"# c #EE8D18", +"$ c #F4931F", +"% c #D78625", +"& c #D88520", +"* c #D98521", +"= c #D98620", +"- c #D78B2D", +"; c #DF8D2A", +": c #DF8F2F", +"> c #DF943B", +", c #D8913C", +"< c #D8923E", +"1 c #DF953E", +"2 c #E28B23", +"3 c #E38B23", +"4 c #EA9023", +"5 c #EB9023", +"6 c #ED9122", +"7 c #ED9123", +"8 c #EE9123", +"9 c #EE9223", +"0 c #F39421", +"q c #F19423", +"w c #F39523", +"e c #F79521", +"r c #F59422", +"t c #F49623", +"y c #F69622", +"u c #F79623", +"i c #F09324", +"p c #F19424", +"a c #F19525", +"s c #F49624", +"d c #F59625", +"f c #F49725", +"g c #F79624", +"h c #F79724", +"j c #F69725", +"k c #F79725", +"l c #F69726", +"z c #F79726", +"x c #F89621", +"c c #F89722", +"v c #F89723", +"b c #F89724", +"n c #F89824", +"m c #F89825", +"M c #F99825", +"N c #F89925", +"B c #F89926", +"V c #F89927", +"C c #F99927", +"Z c #F0972E", +"A c #F7992A", +"S c #F79A2B", +"D c #F79B2C", +"F c #F69A2D", +"G c #F79D2F", +"H c #F89929", +"J c #F89A28", +"K c #F89A29", +"L c #F99A29", +"P c #F99B29", +"I c #F89A2A", +"U c #F89A2B", +"Y c #F99B2B", +"T c #F89B2C", +"R c #F89C2C", +"E c #F99C2D", +"W c #F99C2E", +"Q c #F89D2E", +"! c #F99D2F", +"~ c #E29335", +"^ c #E49639", +"/ c #E2983F", +"( c #F79F35", +") c #F99E31", +"_ c #F89E32", +"` c #F99E32", +"' c #F9A033", +"] c #F9A035", +"[ c #F9A135", +"{ c #F9A036", +"} c #F9A136", +"| c #F9A137", +" . c #F3A03F", +".. c #F7A43F", +"X. c #F8A139", +"o. c #F9A23A", +"O. c #FAA33B", +"+. c #FAA43E", +"@. c #FAA43F", +"#. c #EF9F41", +"$. c #EEA244", +"%. c #ECA34B", +"&. c #F8A440", +"*. c #F9A541", +"=. c #F9A644", +"-. c #F9A947", +";. c #F0A349", +":. c #F5A648", +">. c #F1A74E", +",. c #F7AA4F", +"<. c #E4A458", +"1. c #E4A55B", +"2. c #E8A95E", +"3. c #F2A950", +"4. c #F4AA52", +"5. c #FBAF55", +"6. c #E4A860", +"7. c #EAAC63", +"8. c #EBAF68", +"9. c #F2AF61", +"0. c #EBB16C", +"q. c #F6B568", +"w. c #E3AF71", +"e. c #EBBE89", +"r. c #E0BC93", +"t. c #E3C199", +"y. c #E6C59D", +"u. c #EAC89E", +"i. c #E7C8A2", +"p. c #EACBA6", +"a. c #EBCFAF", +"s. c #F1CCA0", +"d. c #E7CEB1", +"f. c #ECD1B0", +"g. c #E5D2BB", +"h. c #E8D2B8", +"j. c #DFDFDF", +"k. c #E7D5C1", +"l. c #E7D7C4", +"z. c #E5D7C7", +"x. c #E7DACB", +"c. c #EADAC8", +"v. c #E9DCCC", +"b. c #EDDFCE", +"n. c #E5DDD3", +"m. c #E4DFD9", +"M. c #ECE0D1", +"N. c #E4E1DD", +"B. c #EDE3D8", +"V. c #EAE4DD", +"C. c #ECE5DC", +"Z. c #E2E2E2", +"A. c #E5E2E0", +"S. c #E4E4E4", +"D. c #E7E7E7", +"F. c #EAEAE9", +"G. c gray92", +"H. c #EEEEEE", +"J. c None", +/* pixels */ +"J.J.J.J.J.J.J.1 > J.J.J.J.J.J.J.", +"J.J.J.J.J./ ..| ' ( ~ J.J.J.J.J.", +"J.J.J.< *.{ V $ r U W _ - J.J.J.", +"J.J., o.J 0 # <.w.$.F N H % J.J.", +"J.J.o.T e 1.r.k.x.t.S z B u J.J.", +"J.^ [ Y ! #.z.H.M.n.0.d n m 2 J.", +"J.X.) | =. .h.B.5.f.j.;.v B d J.", +": Q M ` &.>.A.V.p.c.l.4.E n d = ", +"; I b A Z 2.D.s.u.F.a.-.} C w & ", +"J.l g y 6.m.G.q.3.b.Z.,.] D 8 J.", +"J.3 k c %.d.C.v.N.S.y.@.L a * J.", +"J.J.j z x 8.i.g.e.9.+.W t 6 J.J.", +"J.J.+ s h G :.7.O.R B s 7 . J.J.", +"J.J.J.O i f P L K d p 5 J.J.J.", +"J.J.J.J.J.@ 9 q i 4 + J.J.J.J.J.", +"J.J.J.J.J.J.J.X o J.J.J.J.J.J.J." +}; diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba94fb46dd9ea20f194a09b75736f0c3c87f73e GIT binary patch literal 32814 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 literal 0 HcmV?d00001 diff --git a/share/pixmaps/bitcoin256.xpm b/share/pixmaps/bitcoin256.xpm new file mode 100644 index 000000000..87bb35cda --- /dev/null +++ b/share/pixmaps/bitcoin256.xpm @@ -0,0 +1,465 @@ +/* XPM */ +static char *bitcoin___[] = { +/* columns rows colors chars-per-pixel */ +"256 256 203 2", +" c #BE741B", +". c #C1761B", +"X c #C6791C", +"o c #CC7C1D", +"O c #D07F1D", +"+ c #C67B21", +"@ c #CC7E21", +"# c #D4821E", +"$ c #D9841F", +"% c #ED8E1D", +"& c #EF911F", +"* c #CF8022", +"= c #D48323", +"- c #DB8621", +"; c #DD8922", +": c #D58729", +"> c #D6882B", +", c #DE8C2A", +"< c #CE8C3C", +"1 c #D28934", +"2 c #D98E32", +"3 c #D28E3C", +"4 c #DF9132", +"5 c #D6903E", +"6 c #DD933B", +"7 c #E58C22", +"8 c #E98F23", +"9 c #E38F2B", +"0 c #E88F28", +"q c #ED9124", +"w c #E6922D", +"e c #EB942B", +"r c #EF982F", +"t c #F59624", +"y c #F89723", +"u c #F79826", +"i c #F89825", +"p c #F1972A", +"a c #F59A2C", +"s c #F89B2B", +"d c #E59534", +"f c #EA9632", +"g c #EE9933", +"h c #E3963B", +"j c #E6993D", +"k c #EC9C3B", +"l c #F49C33", +"z c #F99E32", +"x c #F29E3A", +"c c #F7A037", +"v c #F9A036", +"b c #F5A13C", +"n c #F9A33B", +"m c #CE9147", +"M c #D29245", +"N c #DC9641", +"B c #DD9846", +"V c #D2954B", +"C c #DC9A4B", +"Z c #E59C44", +"A c #EA9E43", +"S c #E39E4B", +"D c #E89F49", +"F c #F09F40", +"G c #EDA145", +"H c #E6A14D", +"J c #EBA34B", +"K c #F4A443", +"L c #F9A642", +"P c #F7A847", +"I c #FAA846", +"U c #F3A64A", +"Y c #F8A748", +"T c #F5A94D", +"R c #FAAA4B", +"E c #E6A454", +"W c #EBA552", +"Q c #EDA856", +"! c #E4A55B", +"~ c #E8A75B", +"^ c #E7A95E", +"/ c #EBA95B", +"( c #F0A751", +") c #F4AB53", +"_ c #FAAE53", +"` c #F4AE5A", +"' c #F8AF59", +"] c #FAB057", +"[ c #F6B15E", +"{ c #FAB25B", +"} c #DFAD6F", +"| c #DCAE77", +" . c #DFB27D", +".. c #E5AA64", +"X. c #E8AB61", +"o. c #E5AE6C", +"O. c #E6B06F", +"+. c #ECB16C", +"@. c #F5B365", +"#. c #FBB562", +"$. c #FBB867", +"%. c #F5B66B", +"&. c #FAB768", +"*. c #F4B86F", +"=. c #FBB96A", +"-. c #E1AE71", +";. c #E5B174", +":. c #EBB573", +">. c #EFB977", +",. c #E5B47A", +"<. c #EEBA7B", +"1. c #F3B770", +"2. c #F3B974", +"3. c #FBBC72", +"4. c #F3BC7B", +"5. c #F8BF7A", +"6. c #FAC079", +"7. c #DCB382", +"8. c #DFBB8F", +"9. c #DABB96", +"0. c #DBBD99", +"q. c #E2B682", +"w. c #E4B985", +"e. c #ECBD84", +"r. c #E3BB8B", +"t. c #EABF8C", +"y. c #F1BE83", +"u. c #E2BE92", +"i. c #D3BDA2", +"p. c #DEC09C", +"a. c #EEC28D", +"s. c #F4C286", +"d. c #F8C282", +"f. c #F3C48B", +"g. c #E7C297", +"h. c #ECC393", +"j. c #E2C29D", +"k. c #EAC69B", +"l. c #ECC89F", +"z. c #F1C694", +"x. c #F2C897", +"c. c #F1CA9B", +"v. c #DBC2A3", +"b. c #D6C2AB", +"n. c #DDC7AD", +"m. c #DEC9AF", +"M. c #D3C4B3", +"N. c #DDCAB3", +"B. c #D2C7B9", +"V. c #D6C9BA", +"C. c #DDCEBB", +"Z. c #DFD0BE", +"A. c #E2C5A2", +"S. c #E8C7A0", +"D. c #E6C9A5", +"F. c #EBCBA4", +"G. c #E2C7A8", +"H. c #E3CAAC", +"J. c #EBCDA9", +"K. c #EFD2AF", +"L. c #F3D1A7", +"P. c #F1D1A9", +"I. c #E4CEB3", +"U. c #E8CFB1", +"Y. c #E1CFBA", +"T. c #E6D0B6", +"R. c #E9D1B4", +"E. c #E4D2BC", +"W. c #EAD4BA", +"Q. c #F4D5B0", +"!. c #F4D9B9", +"~. c #CDCDCD", +"^. c #D5CCC3", +"/. c #D4CFCA", +"(. c #DED2C3", +"). c #D3D1CE", +"_. c #DED6CC", +"`. c #D5D5D5", +"'. c #DBD7D1", +"]. c #DEDAD4", +"[. c #DDDDDC", +"{. c #E3D5C3", +"}. c #E9D7C1", +"|. c #EBD9C4", +" X c #E1D6CA", +".X c #E3D9CD", +"XX c #EADDCD", +"oX c #E1DBD4", +"OX c #E8DFD4", +"+X c #E1DEDB", +"@X c #EDE3D7", +"#X c #E3E1DE", +"$X c #E8E3DC", +"%X c #F6E5D2", +"&X c #F4EBDF", +"*X c #E4E4E4", +"=X c #ECE7E2", +"-X c #EDE9E4", +";X c #ECECEC", +":X c #F0EBE7", +">X c #F4F4F4", +",X c #FEFEFE", +"X>X>X>X;X;X*X[.`.r.n n z v v v v c x l p l x x c c v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X>X>X>X>X;X*X[.`.@.n n v v v v v c g E | S k f r l l l z z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i e X>X,X,X,X,X>X>X;X*X_.R n v v v v v v x e 0.`.`.V.p.;.H f e e p l l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y , X>X,X,X,X,X>X>X;X*XI.L n v v v v n n x g V.`.[.[.[.[.[.(.p.;.S f r l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u y X,X,X,X,X,X>X>X;X*Xa.n n v v v n n n l A `.[.*X*X-X-X*X*X*X[.`.V.9.K z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X-X[.%.n n n n n n n b p o.[.*X;X;X;X>X;X;X*X*X[.`.~.T z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y 0 X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g u.*X-X;X>X>X>X>X>X;X*X*X[.N.L n z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y X>X,X,X,X,X>X>X;X*XI.L L n n n n n n b g C.*X;X>X>X,X,X,X>X>X;X*X[.g.L n z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n l G [.*X;X>X,X,X,X,X>X>X;X*X[.2.n n z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y w X,X,X,X,X,X>X>X-X[.%.L n n n n n n b l o.*X;X>X>X,X,X,X,X,X>X;X*X]._ n v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g j.*X;X>X>X,X,X,X,X,X>X;X*XE.I n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X>X,X,X,X,X>X>X;X*XT.I L n n n n n n b k Z.*X;X>X,X,X,X,X,X>X>X;X*Xl.L n v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y ; X,X,X,X,X,X>X>X;X*Xh.L L n n n n L L x G [.*X;X>X,X,X,X,X,X>X>X;X*X4.n n v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X,X,X,X,X,X>X>X-X[.%.L L n n n L L L l ;.*X;X>X>X,X,X,X,X,X>X;X*X[._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X>X>X;X;X;X;X*X*X*X*X].N.q.! d e e r p q ,.-X;X>X>X,X,X,X,X,X>X;X*XoX_ I L n L L L L K g j.*X;X>X>X,X,X,X,X,X>X;X*XE.Y L n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X>X>X>X>X>X;X;X;X;X*X*X*X*X_.I.r.o.Z w D.;X>X>X,X,X,X,X,X,X>X;X*XW.R I L L L L L L K k Y.*X;X>X,X,X,X,X,X>X>X;X*Xl.L L n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X*X*X*X*X$X}.=X>X>X>X,X,X,X,X,X,X>X;X*Xx.I I L L L L L L x J [.*X;X>X,X,X,X,X,X>X>X;X*X4.L n n v v v v v z z z z z z s s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X>X>X;X&.L L L L L L L L x ;.*X;X>X>X,X,X,X,X,X>X;X*X[.' L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X>X>X@Xb l x x K L L L L k j.*X;X>X>X,X,X,X,X,X>X;X*XE.R L n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X:XW.g.;.H k k k b F k {.;X>X>X,X,X,X,X,X>X>X;X*XS.I L n n n n v v v v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X+XE.j.,.~ j A =X;X>X>X,X,X,X,X,X>X>X;X*X4.I L n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X;X*X*X*X*XXX}.;X>X>X,X,X,X,X,X,X>X>X;X#X{ I n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X;X>X>X>X,X,X,X,X,X,X,X>X>X;X|.R I n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X>X>X;XF.L L n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X;X@.a x b b n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.e.G g l c b n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X+XG...k g l b n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X*X(.w.A g l c c v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X*X'.u.A r l x c v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X].u.k r l c v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X_.q.g p l z v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.C.W p l c v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X[.w.r a l z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-X-X-X*X*X-X;X;X;X;X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.H.g a z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.3.x.R..X+X*X*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X(.k p z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X$.{ { { $.3.f.F.{.[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.W p z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X|.{ ] _ ] { { { { $.3.h.R..X*X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'.k p z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ._ ] _ _ _ _ ] { { { #.$.$.f.T.oX*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.l a z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs._ _ _ _ _ _ _ _ _ ] { { { { { =.l..X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.t z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X+X&.] _ _ _ _ _ _ _ _ _ _ _ _ ] { { { #.k.oX*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.:.t z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.{ { _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] _ { J.*X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.l s z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ _ _ _ _ _ _ _ ] _ _ _ _ _ _ _ _ _ _ _ y.oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.t.u z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ _ _ ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ ' .X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X].&.{ ] _ _ _ ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ R R oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.:.u z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ _ _ ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ I @.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.s z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ ' ] ] ] ] ] { { { ] ] ] _ _ _ _ _ _ _ _ R R _ n k.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.n z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ { ] ] ] ] { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R I T +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.T z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] ] ] { { { { { { { ] ] ] _ _ _ _ _ _ _ _ _ R R R K D.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R K e.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.<.v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.#.{ { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ _ R U / *X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xe.n n v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { ] ] ] ' _ _ _ _ _ _ _ _ R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n n v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T K ,.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.>.n n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T G j.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.n n v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ T J X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X3.#.{ { { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ ) G ..*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.=.#.{ { { { { { { { { { { { { { { { { { { ] ] ' _ _ _ _ T k E.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.L L n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.] { { { { { { { { #.{ { { { { { { { { { { ] ] ] _ _ _ ( A w.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.a.L n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xx.( Q ( ) ` [ [ { #.#.#.{ { { { { { { { { { { ] ] _ ) T D o.*X;X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XOXI.u.O./ Q Q ` ` [ [ [ { { { { { { { { { ] ' ) ( J H r.*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.R I n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X*X_.H.r.;.X./ Q Q ) ) ` ` ` ` ` ) ) ( J H W ,.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.y.I L n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X*X].(.H.u.q.;.^ ^ ~ ~ E E ~ o.r.G. X*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_._ Y L n n n n n v v v z z z z z z z s s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t @ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X*X*X*X*X*X*X[.]..X X XoX+X*X*X*X-X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.f.R I n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X;X-X-X*X*X*X-X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X;X*X X_ R L n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X;X;X;X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.%.R I L n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t - X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X[.k.R R L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.l.] _ I L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X[.l.{ _ Y L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X].h.{ _ R L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X[.T.3.{ ] R I L L L L L n n n n n n n n n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X;X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*XW.s.#.{ _ R I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-XQ.|.OX*X*X*X*X*X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X&X!.L.d.#.{ ] R R I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XXX3.3.3.s.c.R..X[.*X*X*X-X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X%X{ L R _ _ R R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-XK.&.=.=.&.=.3.3.d.c.R..X[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XJ.J K Y R R Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.$.#.#.#.#.&.&.=.=.3.3.f.F.}.+X*X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;XOX:.K U R R I I I I I L L L L L L n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X+X3.$.#.{ { #.#.#.#.$.$.&.=.=.3.6.c.W.+X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*Xj.K K R R I I I I I L L L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.&.#.{ { { { #.#.#.#.#.#.#.#.$.$.=.=.5.J..X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.K K R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { #.#.#.#.#.#.#.#.{ #.#.$.$.$.=.z.{.*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*XC.U K R I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i u q * s u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u u u s s s s s s s s s s s z z z z z z z v v v v v n n n n n n n n L L L L L L I I K A Z.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.#.{ { { { { #.#.#.#.{ { { { { { { #.#.#.#.$.z.{.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XC.b K Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i u q + X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.3.#.{ { { { { { #.#.#.{ { { { { { { { { { { #.#.#.$.F.+X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.H.b P I I I I I L L L L L n n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { { { { #.{ 2.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.e.b Y I I I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { { { { { { { { { { { { { U.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X].T L Y I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { { { { { { { { { ] { { _ R.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X*XD.L R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] { ' R T.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.` L I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] ] _ ] _ R oX*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.g.n I Y I I I I L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] _ _ _ _ _ ] Y <.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X(.I I I I I I L L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ T .X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L I I I L L L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ P g.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.e.n I L L L L L L L L L L n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { { ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ Y +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xg.L I L L L L L L L L L n n n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { ] ] ] { { { { { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ T Q #X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.I I L L L L L L L n n n n n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { ] ] ] ] { { { { { { { ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Y W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XI.I I L L L L L n n n n n n n n n n n n n n n v v v v v v z z z z z z z s s s s s s s s s s u u u u u i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ ] ] ] ] ] { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R T W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L L L L n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ ] ] ] ] { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R K X.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L n n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i t q @ X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { _ _ _ ] ] ] ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R x q.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.R L n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R T k G.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XS.I L n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X,X,X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X&.{ _ _ _ _ _ ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R K A oX;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s u u u i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.{ ] _ _ _ _ _ ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R U k u.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.2.L L n n n n n n n n n v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s u u u u i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.R _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R T k D +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.' L n n n n n n n n v v v v v v v z v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.K G G U ) ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R R U A j {.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-XXXH.w.X.J J J T ) ) ) _ _ _ _ _ _ _ _ R R R R R R R R R R R Y K k D Y.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.L L n n n n v v v v v v v v z z z z z z z z z z z z z s z s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i u t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X#X(.A.q...H J J U U T T T T R R R R R R R R R Y Y U K k A ;..X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.4.L n n n v v v v v v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i t q * X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X[.(.H.u.,.^ J D G A J K K U U U U K k k k A E w.Y.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v v v v v v v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i t q X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X;X;X;X-X*X*X*X*X[._.N.A.u.;.;...E E E E ..;.q.j.I.+X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.I L n v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i t 8 X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X-X*X*X*X*X*X*X*X+X+X+X+X*X*X*X*X*X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.1.L n v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i u q ; X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X XR L n v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i t q X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.a.L n v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i t 8 X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X]._ L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.a.L n v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.R L n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.2.L n z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u s u u u u u u u u i i i i i i i i i i i i i i i i i i t q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.D.L L v z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X XR L n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X,X,X,X>X>X>X>X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'._ I n z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u i u u i i i i i i i i i i i i i i i i i i i i i i t q o X>X,X,X,X,X,X,X>X>X>X=X;X-X-X-X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X].%.L L z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X>X>X;X=X=.5.c.W.oX*X*X-X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X_.%.I L z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X,X>X>X;X|._ _ _ { #.4.l.}.$X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.E.{ I L v z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*XF.R R R R _ _ { { { 4.-X>X>X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X;X;X*X*X[.k._ I n z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X;X*X4.R I I I I R R R b U -X>X>X,X,X,X,X,X,X,X,X>X>X>X>X>X;X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X;X;X;X-X*X*X[.T.*.R L n z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X>X;X*X+X] R I L I I I I P x t.;X>X>X,X,X,X,X,X,X,X>X>X;X;X;X;X-X-X-X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X*X*X*X[.].U.4.R I L v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XE.R Y L L I I I I K k I.-X;X>X,X,X,X,X,X,X>X>X;X|.f.J.W..X[.[.*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X[._.I.h.#.R L L n z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X,X,X,X,X,X>X>X;X*Xl.I I L L L I I P K A oX-X>X>X,X,X,X,X,X>X>X;X;Xs.R _ _ { #.4.y.S.l.T.{.{. XoXoXoXoX].oX{.{.E.k.a.2.{ _ I L n v z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X,X,X,X,X,X>X>X;X[.2.I I L L L L I L x ^ *X;X>X>X,X,X,X,X,X>X>X;X*X#.I I I I Y I R I _ R _ ] { { [ { { { { ] _ R R I I L n n v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X>X,X,X,X,X,X>X;X*X]._ Y L L L L L I L k r.*X;X>X>X,X,X,X,X,X>X;X-X.XR L n n n n n n L L L L L L L n L n n n L n n n c v z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XT.R I L L L L L L K k H.*X;X>X>X,X,X,X,X>X>X;X*XJ.L L n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*Xk.I I n L L L L L b k ].*X;X>X,X,X,X,X,X>X>X;X*Xy.L n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X-X[.2.L L n L L L L L l ^ [.-X>X>X,X,X,X,X,X>X;X*X[.[ L n n n v v v v v v v z z v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X;X*X]._ L L n L L L L K g r.*X;X>X>X,X,X,X,X,X>X;X*X{.R L n v v v v v v v z z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X,X,X,X,X>X>X;X*XE.I L n n n L L L b g H.*X;X>X>X,X,X,X,X>X>X;X*XF.L L v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 8 X>X>X,X>X>X>X;X*Xk.L L n n n n L L x k _.*X;X>X,X,X,X,X,X>X>X;X*Xy.n n v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q # X>X>X>X>X;X*X[.2.L L n n n n n b l ~ [.-X>X>X,X,X,X,X,X>X;X*X[.' L n v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X>X,X,X,X,X,X>X;X*X{.I n c v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X>X>X;X*XF.L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X>X>X;X*X4.n n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 .L n n n n n n b l E [.*X;X>X>X,X,X,X>X>X;X*X[.' n v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X>X>X>X>X;X*X{.I n z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X>X;X;X*X[.S.n n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 L{LUZ0=k+|#_xt@kpZEK7f4!b~NBcd>3YrQK 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 c #8F6A16", -", c #816218", -"< c #88691C", -"1 c #926D12", -"2 c #936F1C", -"3 c #997417", -"4 c #94721E", -"5 c #9B761C", -"6 c #9F781C", -"7 c #A17B1E", -"8 c #826622", -"9 c #916E20", -"0 c #967425", -"q c #9D7420", -"w c #9C7923", -"e c #997728", -"r c #99792C", -"t c #A37D23", -"y c #A37F2C", -"u c #A68125", -"i c #AB8225", -"p c #A5832B", -"a c #AA852C", -"s c #B28A2C", -"d c #A58233", -"f c #AC8734", -"g c #AE8C33", -"h c #AC8C3C", -"j c #B28C33", -"k c #B98E34", -"l c #B28D3D", -"z c #B59136", -"x c #BC9335", -"c c #B3913E", -"v c #BC933A", -"b c #BF9A3D", -"n c #C19235", -"m c #C2953C", -"M c #C39B3C", -"N c #CA9C3D", -"B c #B59343", -"V c #BE9642", -"C c #B69A44", -"Z c #BD9A45", -"A c #B49649", -"S c #BB9A49", -"D c #BB9F52", -"F c #BFA256", -"G c #C49C43", -"H c #CA9D41", -"J c #C59D4A", -"K c #C99E4D", -"L c #C3A144", -"P c #CDA244", -"I c #CFAA47", -"U c #C3A14D", -"Y c #CDA24A", -"T c #CCAB49", -"R c #D2A644", -"E c #D2A54B", -"W c #D6AA4C", -"Q c #DAAE4E", -"! c #DAB04F", -"~ c #C7A656", -"^ c #CDA452", -"/ c #CFAC52", -"( c #C0A65E", -") c #CEA75A", -"_ c #CCAC59", -"` c #D2AB53", -"' c #DCAF52", -"] c #D6AD5A", -"[ c #D9AE5B", -"{ c #DCB556", -"} c #DFB855", -"| c #D6B25F", -" . c #DCB35C", -".. c #DEBE5E", -"X. c #E2B656", -"o. c #E1B55A", -"O. c #E6BC5D", -"+. c #E9BD5E", -"@. c #C3AA63", -"#. c #CCAD62", -"$. c #D4AF62", -"%. c #CDB565", -"&. c #CEB46D", -"*. c #D7B164", -"=. c #DBB362", -"-. c #D6BD64", -";. c #DDBA64", -":. c #D3B66C", -">. c #DFB86B", -",. c #CEB772", -"<. c #D0B771", -"1. c #D4BA73", -"2. c #D9BE77", -"3. c #D6BE79", -"4. c #D8BF7A", -"5. c #E4BB62", -"6. c #E9BF64", -"7. c #E4BC69", -"8. c #E9BF69", -"9. c #E0BB71", -"0. c #E9C05E", -"q. c #D2C279", -"w. c #DBC27C", -"e. c #E2C667", -"r. c #EDC364", -"t. c #E3C16E", -"y. c #ECC46C", -"u. c #EDCC6C", -"i. c #F1C764", -"p. c #F5CA66", -"a. c #F9CD67", -"s. c #F5CC6A", -"d. c #F9CD6B", -"f. c #FBD36F", -"g. c #EDC572", -"h. c #E5CF77", -"j. c #ECCA74", -"k. c #E0C67E", -"l. c #EFCE78", -"z. c #F6CE72", -"x. c #FBCF71", -"c. c #F4CE79", -"v. c #F4D273", -"b. c #FCD473", -"n. c #F4DC75", -"m. c #FEDA74", -"M. c #F6D77C", -"N. c #FBD47A", -"B. c #F1DA7B", -"V. c #FDDA7C", -"C. c #FEE27D", -"Z. c #DDC683", -"A. c #DFC884", -"S. c #E4CA84", -"D. c #E3CC89", -"F. c #E7D183", -"G. c #EFD280", -"H. c #EFDC82", -"J. c #ECD48D", -"K. c #EFDA8C", -"L. c #F9D783", -"P. c #F2DF83", -"I. c #FCDB83", -"U. c #F5DC8F", -"Y. c #FADD8B", -"T. c #EBD593", -"R. c #EFDA99", -"E. c #F3DD93", -"W. c #F3DF9F", -"Q. c #FFE385", -"!. c #FEE986", -"~. c #FDE48C", -"^. c #FEEC8E", -"/. c #ECE199", -"(. c #F6E591", -"). c #FEE494", -"_. c #FEEB93", -"`. c #FEE69A", -"'. c #FFEB9B", -"]. c #FFF197", -"[. c #FFF39B", -"{. c #FEF99B", -"}. c #F6E2A2", -"|. c #F9E5A5", -" X c #F7E9A5", -".X c #FEECA4", -"XX c #FBE7A8", -"oX c #FDEAAB", -"OX c #F7F2AA", -"+X c #FEF2AC", -"@X c #FDF4B4", -"#X c #FFFABA", -"$X c #FFFEC2", -"%X c None", +"32 32 102 2", +" c #CC7D1D", +". c #D5831F", +"X c #D48221", +"o c #D98621", +"O c #DC8820", +"+ c #DC8D2C", +"@ c #D98F36", +"# c #D68F39", +"$ c #DD943E", +"% c #E28B23", +"& c #E98F24", +"* c #E18F2D", +"= c #ED9124", +"- c #EC942A", +"; c #F59624", +": c #F89724", +"> c #F79827", +", c #F89825", +"< c #F0962B", +"1 c #F59A2D", +"2 c #F99B2B", +"3 c #EC9732", +"4 c #EC9A37", +"5 c #E2963B", +"6 c #E6983A", +"7 c #EC9C3B", +"8 c #F69D33", +"9 c #F99E32", +"0 c #F49E3A", +"q c #F9A036", +"w c #F6A13C", +"e c #F9A33B", +"r c #D79341", +"t c #DC9641", +"y c #E39A43", +"u c #EA9D42", +"i c #EFA041", +"p c #EDA34B", +"a c #F5A443", +"s c #F9A643", +"d c #FAA846", +"f c #F2A64C", +"g c #F9AA4B", +"h c #E5A251", +"j c #ECA756", +"k c #EBA758", +"l c #FAAF57", +"z c #FBB057", +"x c #FBB25B", +"c c #DFB179", +"v c #E4AA65", +"b c #EBAE64", +"n c #E9AF69", +"m c #FBB665", +"M c #F1B46A", +"N c #F8B96D", +"B c #E5B071", +"V c #EBB777", +"C c #EEB877", +"Z c #E7B478", +"A c #EBB97D", +"S c #F0B671", +"D c #F2B871", +"F c #EFBC80", +"G c #E6BD8D", +"H c #EDBF88", +"J c #E6BF90", +"K c #F1C187", +"L c #F1C288", +"P c #E5C093", +"I c #EEC493", +"U c #E1C19B", +"Y c #E9C69C", +"T c #ECC89D", +"R c #F1C897", +"E c #DFC5A4", +"W c #DBCBB8", +"Q c #E2C7A7", +"! c #EBCBA6", +"~ c #E6CBAB", +"^ c #E9D2B7", +"/ c #E5D1B9", +"( c #EBD6BD", +") c #EFD9BE", +"_ c #DDD0C2", +"` c #DCD7D2", +"' c #DEDEDE", +"] c #ECDAC5", +"[ c #EDDECB", +"{ c #E9E0D5", +"} c #E7E0D9", +"| c #E9E2DB", +" . c #EFE8DF", +".. c #E5E5E5", +"X. c #EBE7E2", +"o. c #EFEAE6", +"O. c #ECECEC", +"+. c #F2ECE6", +"@. c #F1F0EE", +"#. c #F4F4F4", +"$. c #FBFBFB", +"%. c None", /* pixels */ -"%X%X%X%X%X%X%X%X%X%X%X%Xp t 6 5 w t w %X%X%X%X%X%X%X%X%X%X%X%X%X", -"%X%X%X%X%X%X%X%X%Xu u x I X.0.s.u.0.W x 7 4 %X%X%X%X%X%X%X%X%X%X", -"%X%X%X%X%X%X%Xy i I i.a.f.m.m.b.f.s.a.s.i.W 7 > %X%X%X%X%X%X%X%X", -"%X%X%X%X%X%Xt M 0.a.m.m.m.m.f.d.p.p.p.f.d.f.i.b 1 < %X%X%X%X%X%X", -"%X%X%X%X%X7 ! d.f.f.m.f.+.W P R I Q 5.v.V.V.z.f.{ 5 + %X%X%X%X%X", -"%X%X%X%Xu X.f.m.m.f.' H s ~ V y _ Z J o.g.L.L.Q.!.e.5 X %X%X%X%X", -"%X%X%Xu X.b.C.m.+.N m n t }.3.> }.w.V 5.y.y.Y.[.^.^.-.1 + %X%X%X", -"%X%Xt P m.N.m.X.v v v k 6 }.1.: /.4.c 7.N.N.v.!.{.{.^.L & %X%X%X", -"%X%Xg Y.Y.V.+.m k a t t : }.1.% }.1.r | l.B.M.b.!.{.^.n.7 X %X%X", -"%Xp -._.'.Y.' Y n D.}.}.|.oXXX|.oX XT.w.F _ j.v.v._.^.C.T & @ %X", -"%Xa (.'.'.9.[ [ K S.}.oXoXoXoXXXoXoXoXoX XD / s.d.v.!.C.v.3 o %X", -"%XU '.'.Y.[ [ [ [ J f <.oXoX( 2 f S J.oXoXT.j r.s.i.C.C.C.z X %X", -"p e.'.'.F. .=.=.=.=.) 1.oXoX@.f . .F oXoX}.a +.i.i.b.C.m.I X O ", -"u w.'.[.j.5.8.7.7.7.] 2.oXoX@.y W c &.oXoXZ.k r.s.i.s.V.m.} = o ", -"u H.[.{.y.8.y.g.8.g.7.2.oXoXA.@.&.D.oXoXT.e G +.O.O.5.V.m.0.- o ", -"u !.].[.r.8.y.g.g.g.7.4.oXoXoXoXoXoXoXoXoX<.y W X.o.o.m.m.0.- o ", -"u B._._.5.5.8.y.g.c.g.w.oXoX,.h A F <..XoXoX1.k ' ' ' V.N.r.- ", -"u u.Q.~.r.6.z.N.V.I.v.k.oXoX@.B | _ c 1.oXoX}.a ' ' O.I.b.O.= o ", -"u ..Q.Q.v.i.s.c.N.L.l.Z.oXoX@.B t.=.S &.oXoXXXy Y R +.N.b.Q % o ", -"t T C.I.I.6.u.z.z.5.S 1.oXoX@.e B h D |.oXoXS.f Y Y 6.d.d.n X O ", -"%Xs m.V.Q.r.r.z.5.<.}.oXoXoXXXW.}.oXoXoXoXW.h G H R a.p.s.7 %X", -"%X7 O.V.V.v.+.r.` 4.oXoXoXoXoXoXoXoXXXR.<.h v N N o.a.p.Q = %X", -"%Xw x v.v.v.r.+. .Z l d e }.Z.r }.3.d l V G n n R a.s.a.s X O %X", -"%X%X6 { v.l.v.+.O.5.=.^ d }.4.9 }.1.f J G m m G d.d.x.Q = %X%X", -"%X%X%Xs u.v.v.v.r.6.o. .l }.4.9 W.4.l ^ ^ J ) c.N.N.y.7 X O %X%X", -"%X%X%X5 z v.v.M.I.g.;. .J 1.#.B 1.#.) 7.$.S..X'.W.Y.j $ %X%X%X", -"%X%X%X%X5 b N.Y.~.).Y.j.5.$.=.=.$.*.2.J.@X$X#X#XoXC $ %X%X%X%X", -"%X%X%X%X%X3 z U.@X+X`.`.`.(.E.E.E.|.@X@X#X#X#X/.j % %X%X%X%X%X", -"%X%X%X%X%X%Xw a q.OX|.).`._.'.'.XX.X.X+X+X X%.w X o %X%X%X%X%X%X", -"%X%X%X%X%X%X%X%Xw a _ j.~.~.).).`.`.`.F._ t & . # %X%X%X%X%X%X%X", -"%X%X%X%X%X%X%X%X%X%X4 3 t z L U Z z t 1 $ . 8 %X%X%X%X%X%X%X%X%X", -"%X%X%X%X%X%X%X%X%X%X%X%X%X< ; & + + , 8 %X%X%X%X%X%X%X%X%X%X%X%X" +"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.%.%.%.t 5 5 $ %.%.%.%.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.r u w q 9 9 9 8 4 # %.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.y s e 9 2 , , , : > 2 9 q 5 %.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.s q 2 , , , , : , > 2 2 > > 2 9 %.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.t e 1 , , , , : : ; > 2 9 9 2 , , > 2 + %.%.%.%.%.%.", +"%.%.%.%.%.$ e 2 , , , , , , ; u u 8 1 1 2 > , , > > + %.%.%.%.%.", +"%.%.%.%.%.e 2 , , : > ; ; > < ` ` 0 c n 1 2 , , , > , %.%.%.%.%.", +"%.%.%.%.e 1 , , , , ; h v - 3 ..! w ' _ 9 2 > , , , > : %.%.%.%.", +"%.%.%.6 q , : , > 2 > W ..| [ #.H V ..D 9 9 2 , , , , , % %.%.%.", +"%.%.%.e 2 , > 2 2 2 9 b ! #.$.$.#.#.#.Y i 1 2 > , , , > ; %.%.%.", +"%.%.@ q > 2 2 2 9 q e q 0 o.$.+.) { #.#.| b 2 2 , , , , : X %.%.", +"%.%.4 9 2 2 9 q e e s w b O.#.( m x I @.$...f > > , , , : & %.%.", +"%.%.8 > 2 2 9 e s d g a P #.#.L x l a [ $.#.A 2 2 , : , , ; %.%.", +"%.+ 1 , , 2 2 q e d g f / $.#.T n k Z o.$.O.M 9 2 > , , , ; X %.", +"%.* 2 , , , 2 9 q e s f X.$.#.O.O.O.#.$.+.Y g e 9 2 , , , ; o %.", +"%.* 2 , , , 2 2 q e w n O.$.[ R ( O.$.$.[ d s e 9 2 2 , , ; o %.", +"%.+ 2 , , , > 2 8 8 1 G #.#.T m m N ] #.#.~ s e e 9 2 > : ; X %.", +"%.%.> , , , , 2 < v B [ $.O.m z z s b #.$...g e e q 9 2 ; = %.%.", +"%.%.= : , , , : 7 ' O.#.$.@.C j p u ~ #.$.} g q 9 9 2 2 ; % %.%.", +"%.%.o , , , , : 0 G ^ .$.#.O.X.{ X.#.$.#.Y e 9 2 2 > , ; %.%.", +"%.%.%., : , , , 2 2 2 M O.) ] #.#.#.#.O./ d 9 2 > , , ; = %.%.%.", +"%.%.%.& ; , , , , 2 ; Q ..g F O.K A H S s 9 2 > , : , ; o %.%.%.", +"%.%.%.%.; ; , , , , 2 E _ d ' ..d q q 9 2 > , : , , ; = %.%.%.%.", +"%.%.%.%.%.; : , , , 2 q d g U J e 2 2 > , , , , , ; = %.%.%.%.%.", +"%.%.%.%.%.o ; : , , , 2 9 q 9 q 9 > , : , , , , ; = . %.%.%.%.%.", +"%.%.%.%.%.%.. ; ; , , > 2 2 2 > , , , , , , , ; = %.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.= ; : > 2 2 , , : , , , , ; ; & %.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.. = ; > : , , , , ; ; = = X %.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%. % = ; ; ; ; & O %.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.%.%.%. X X %.%.%.%.%.%.%.%.%.%.%.%.%.%.", +"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%." }; diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png new file mode 100644 index 0000000000000000000000000000000000000000..8aedee811f740696f8957f78a96f0882010d6687 GIT binary patch literal 6026 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 c #FD8E0C", +", c #FF910E", +"< c #F98F14", +"1 c #F79117", +"2 c #FD9314", +"3 c #FC951B", +"4 c #FE9A1D", +"5 c #CA8E22", +"6 c #CC8E2A", +"7 c #D48D23", +"8 c #C39223", +"9 c #CE9925", +"0 c #D19C25", +"q c #D19329", +"w c #D5992B", +"e c #DD9D33", +"r c #D69F3C", +"t c #E29425", +"y c #E79925", +"u c #EA9926", +"i c #E69A2C", +"p c #F79625", +"a c #F99524", +"s c #F79825", +"d c #F89825", +"f c #F3962A", +"g c #F69B2C", +"h c #F89B2B", +"j c #E19F30", +"k c #EE9B34", +"l c #F49D33", +"z c #F99E32", +"x c #F39F3B", +"c c #DFA731", +"v c #D7A43D", +"b c #DCA63C", +"n c #EEA328", +"m c #FFA225", +"M c #FFAB26", +"N c #F3A529", +"B c #FEA429", +"V c #F4AB2A", +"C c #FFAC2A", +"Z c #FFB325", +"A c #FFB42C", +"S c #FFBB2D", +"D c #E3A335", +"F c #E5A438", +"G c #EDA03D", +"H c #F7A037", +"J c #FAA135", +"K c #F3AB31", +"L c #FEAB31", +"P c #F4A13C", +"I c #F9A33B", +"U c #FDB432", +"Y c #FFBF37", +"T c #FFC12F", +"R c #FFC230", +"E c #FFC03E", +"W c #DFAF41", +"Q c #ECA34D", +"! c #EDA84E", +"~ c #F2A343", +"^ c #FAA642", +"/ c #FAA846", +"( c #F1A74C", +") c #F6A94F", +"_ c #FAAA4A", +"` c #E7A451", +"' c #ECA754", +"] c #EFAA56", +"[ c #ECAC5B", +"{ c #F3AA52", +"} c #FCAE52", +"| c #FBB056", +" . c #FBB25C", +".. c #E7AB61", +"X. c #ECB067", +"o. c #E7B36D", +"O. c #EBB36C", +"+. c #F2B163", +"@. c #FCB460", +"#. c #F0B56B", +"$. c #E3B274", +"%. c #EDB672", +"&. c #EDB877", +"*. c #E2B57C", +"=. c #ECB97B", +"-. c #E4BA83", +";. c #EBBD83", +":. c #E7BF8D", +">. c #EBBD88", +",. c #E9C08C", +"<. c #E7C496", +"1. c #EBC393", +"2. c #EBC997", +"3. c #E7C49A", +"4. c #E9C69A", +"5. c #E3CA9D", +"6. c #E9C89E", +"7. c #DCC9AE", +"8. c #DDCBB2", +"9. c #E3C7A2", +"0. c #E5CAA3", +"q. c #E9CBA3", +"w. c #E5CEAB", +"e. c #E8CEAA", +"r. c #E4D4AC", +"t. c #EBD2AF", +"y. c #E7CFB2", +"u. c #E1D4B4", +"i. c #E8D5B6", +"p. c #E5D7BB", +"a. c #E9D6BB", +"s. c #E5D8B9", +"d. c #EAD8BE", +"f. c #F0D6B4", +"g. c #DFDFC6", +"h. c #E3D6C1", +"j. c #E9D7C0", +"k. c #E6DAC5", +"l. c #EBDCC7", +"z. c #E5DCCA", +"x. c #EADEC9", +"c. c #E8DFD0", +"v. c #D7E2D9", +"b. c #E3E0C9", +"n. c #EEE2CB", +"m. c #E6E1D4", +"M. c #E9E2D3", +"N. c #E4E4DC", +"B. c #E9E5DE", +"V. c #F4EDDE", +"C. c #DFE8E6", +"Z. c #DEEEE8", +"A. c #DFF2F3", +"S. c #DDFFFF", +"D. c #E1E6E0", +"F. c #E8E6E2", +"G. c #E8E9E5", +"H. c #E5EFEC", +"J. c #E8E9EA", +"K. c #EAF3EE", +"L. c #F3F3EB", +"P. c #E7EDF2", +"I. c #E8EEF3", +"U. c #E7F4F7", +"Y. c #E9F0F7", +"T. c #EBF5FD", +"R. c #E4FEFF", +"E. c #ECFCFF", +"W. c #F4F5F4", +"Q. c #F4FFFF", +"!. c #FEFFFF", +"~. c None", +/* pixels */ +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.F L h C C A A A A C C h L e ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.D N C m d d a a p a a p a a d m m C N j ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.- K M m a p s d d d d d d d d d d d d s p d m M V % ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.Y M d a d d d d d d d d d d d d d d d d h h d s a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.E m 4 a d d d d d d d d d d d d d d d d d d h h h d d d a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.C 4 a d d d d d d d d d d d d d d d d d h h h h h h d d d d d a m C ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.W S a p d d d d d d d d d d d d d d d d h h h h g g h h h d d d d d p a S c ~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.v M a s d d d d d d d d d d d d d d d h h h h h g z z g h h d d d d d d s a C w ~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.r Z a d d d d d d d d d d d d d d d g 4 : 2 h z z z z z h h h h d d d d d d d a S q ~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.b Z a d d d d d d d d d d d d d d h h 4 x $.l a z H h h H z h h h d d d d d d d d a A w ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.T a s d d d d d d d d d d d d h h h g : $.R.T.7.a B x f > a H h h d d d d d d d d s a R ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.U a s d d d d d d d d d d d d h h h h z : e.!.!.p.2 3 8.D.5.' a h h h d d d d d d d d p d A ~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.U M p d d d d d d d d d d h h 1 : : 2 h h p B.!.Q.%., l J.!.R.-.> z h h h d d d d d d d d p C N ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.S a d d d d d d d d d d h d 3 7.r.O.G p ; k E.!.T.( , [ E.!.T.~ 4 z h h h d d d d d d d d d a S ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.V d s d d d d d d d d h h h 2 l E.!.Q.T.m.:.q.!.!.l.: : -.Q.!.c.a z z z g h h d d d d d d d d s m A ~.~.~.~.~.~.~.", +"~.~.~.~.~.~.@ S a d d d d d d d h h h h z : *.R.!.!.!.!.Q.!.!.!.V.,.Q d.!.Q.1.2 I z z h h h d d d d d d d d d a S X ~.~.~.~.~.~.", +"~.~.~.~.~.~.U d s d d d d d h h h h h g z a [ 5.M.Q.!.!.!.!.!.!.!.Q.E.!.!.Q.&.; 3 J H z h h h d d d d d d d d s h C ~.~.~.~.~.~.", +"~.~.~.~.~.~.S a d d d d h h h h h h z z z I d > < %.W.!.!.!.!.!.!.!.!.!.!.!.W.s.[ > 4 H g h h d d d d d d d d d a S ~.~.~.~.~.~.", +"~.~.~.~.~.i M p d d d h h h h g z z z z J H I I J > x.!.!.!.!.Q.T.E.Q.!.!.!.!.!.E.u.f 2 H h h h d d d d d d d d p C 7 ~.~.~.~.~.", +"~.~.~.~.~.C a d h h h h h g g z z z J J I I I I J P J.!.!.!.!.d.P =.e.G.E.!.!.!.!.Q.Z.f 2 z h h d d d d d d d d d d A ~.~.~.~.~.", +"~.~.~.~.~.A a h h h h h g z z z J H I I I I ^ / d X.E.!.!.!.Q.1.4 I J I ;.U.!.!.!.!.!.N.1 h g h h d d d d d d d d a S ~.~.~.~.~.", +"~.~.~.~.6 C p d h h h z z J J J I I I I ^ ^ ^ _ a 3.Q.!.!.!.E.#.I . ._ 3 ] K.!.!.!.!.E.O., z h h h d d d d d d d p A + ~.~.~.~.", +"~.~.~.~.i B d d h h h g z J I I I I ^ ^ ^ / / _ h k.!.!.!.!.J.) } . .| .3 6.Q.!.!.!.Q.q.> z g h h d d d d d d d d B t ~.~.~.~.", +"~.~.~.~.B d d d d h h h z z J I I ^ / / / _ _ ^ ( I.!.!.!.Q.d.I . . .| .d 1.Q.!.!.!.Q.q.2 z h h h d d d d d d d d d B ~.~.~.~.", +"~.~.~.~.C a d d d d h h g z J H I ^ ^ / _ _ } J %.E.!.!.!.Q.;.4 _ } | } J f m.!.!.!.!.Q.;.2 J z g h h d d d d d d d a A ~.~.~.~.", +"~.~.~.~.C a d d d d h h h z z J I I ^ ^ / _ } z 6.Q.!.!.!.!.n.<.&.+.{ ) ] h.Q.!.!.!.!.R.~ d H z z h h h d d d d d d a A ~.~.~.~.", +"~.~.~.~.A a d d d d d h h g z z H I I ^ / _ _ z k.!.!.!.!.!.!.Q.E.I.F.F.T.Q.!.!.!.!.E.9.2 I J z z h h h d d d d d d d A ~.~.~.~.", +"~.~.~.~.S a d d d d d h h h z z J I I ^ ^ / I ( P.!.!.!.!.Q.Q.!.!.!.!.!.!.!.!.!.!.E.w.d J I I J z h h h d d d d d d d A ~.~.~.~.", +"~.~.~.~.A a d d d d d d h h h z J J I I ^ / h O.E.!.!.!.Q.f.1.z.Y.E.!.!.!.!.!.!.L.! , ^ / I I H z z h h h d d d d d d A ~.~.~.~.", +"~.~.~.~.S p d d d d d d h h h z z J I I ^ / d <.Q.!.!.!.E.+.d _ +.>.k.E.!.!.!.!.Q.s.P J _ ^ I I J z z h h h d d d d d A ~.~.~.~.", +"~.~.~.~.C a d d d d d d d h h g z z H I I ^ d k.!.!.!.!.J.{ | @.} I I O.H.!.!.!.!.Q.C.l I ^ I I H J z g h h d d d d a A ~.~.~.~.", +"~.~.~.~.B a d d d d d d d h h h h z z J I J x P.!.!.!.Q.j.I . . . . .B { K.!.!.!.!.Q.0.a / ^ I I J z z h h h d d d a A ~.~.~.~.", +"~.~.~.~.B d d d d d d d d d h h h J h f 2 ; [ E.!.!.!.Q.1.I . . .| | .d 4.Q.!.!.!.!.m.z I ^ I I I J z h h h h d d d B ~.~.~.~.", +"~.~.~.~.u B d d d d d d d d h h z , ' v.q.X.M.!.!.!.!.E.#.^ . .| } } } d >.Q.!.!.!.!.F.x J I I I J J z z h h h d d C t ~.~.~.~.", +"~.~.~.~.7 C p d d d d d d d d h h : y.Q.Q.Q.!.!.!.!.!.B.d B / _ } } } J 1 k.!.!.!.!.!.c.s J I H J J z z z h h h h s A + ~.~.~.~.", +"~.~.~.~.~.A a d d d d d d d d h > ` R.!.!.!.!.!.!.!.!.L.q.=.[ ~ z h h l 0.Q.!.!.!.!.Q.q.2 I J J z z h h h h h h h a S ~.~.~.~.~.", +"~.~.~.~.~.C d d d d d d d d d d > ..g.Y.E.Q.!.!.!.!.!.!.Q.E.T.B.k.a.d.P.Q.!.!.!.!.!.E.[ 2 J z z z g h h h h d d d d C ~.~.~.~.~.", +"~.~.~.~.~.y C p d d d d d d d d g 3 > l [ <.x.W.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.Q.z.> z z z h h h h h d d d d p C 7 ~.~.~.~.~.", +"~.~.~.~.~.~.S a d d d d d d d d d h h 3 , > ; =.Q.!.W.T.Q.!.!.!.!.!.!.!.!.!.!.!.Q.A.g 2 z h h h h h h d d d d d a S ~.~.~.~.~.~.", +"~.~.~.~.~.~.C h s d d d d d d d d d h g z H : <.!.!.t.l &.V.!.!.Q.Q.Q.Q.!.Q.Q.E.b.l > H h h h h h d d d d d d s m C ~.~.~.~.~.~.", +"~.~.~.~.~.~.X S a d d d d d d d d d h h h h p N.!.Q.=.: < c.!.Q.2.&.e.a.d.i.6.[ < 2 z h h h h d d d d d d d d a S ~.~.~.~.~.~.", +"~.~.~.~.~.~.~.A h s d d d d d d d d d h g 2 ~ E.!.E.{ 2 [ E.!.T.l : 2 1 3 2 > > h z h h h h d d d d d d d d s m A ~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.S a d d d d d d d d d h h : -.R.!.B.h 2 =.Q.!.M.p z z z h h z g h h h d d d d d d d d d d d a S ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.N C p d d d d d d d d d h 3 ' 2.N.9.2 3 z.!.!.q.> J z h h h h h h d d d d d d d d d d d d p C n ~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.S h p d d d d d d d d d z 3 : p l J g 8.T.S.O.> z h h h h h d d d d d d d d d d d d d p h S ~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.S a s d d d d d d d d h h z d h I J a P o.P d g h h h d d d d d d d d d d d d d d s a S ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.* S a s d d d d d d d d h h g z J J h 3 > d z h h h d d d d d d d d d d d d d d s a S * ~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.$ T a s d d d d d d d h h h z z z h g g h h d d d d d d d d d d d d d d d d s a T O ~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.& S a p d d d d d d h h h z g h h h h h d d d d d d d d d d d d d d d d p a S # ~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.8 S d p d d d d d d h h g h h h h d d d d d d d d d d d d d d d d d p h S = ~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.S A a s d d d d h h h h h d d d d d d d d d d d d d d d d d s a A S ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.0 T m p d d d d h h h d d d d d d d d d d d d d d d d d p B S 9 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.V S m a p d h d d d d d d d d d d d d d d d d p a m S V ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.o V S C d p p d d d d d d d d d d d d p p d C S N . ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.5 C S A B d d a a d d a a a d B A S C 5 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.O t B A A A A A A A A B t O ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~." +}; diff --git a/share/pixmaps/bitcoin80.xpm b/share/pixmaps/bitcoin80.xpm deleted file mode 100644 index c3c816e92..000000000 --- a/share/pixmaps/bitcoin80.xpm +++ /dev/null @@ -1,292 +0,0 @@ -/* XPM */ -static const char * bitcoin80_xpm[] = { -/* columns rows colors chars-per-pixel */ -"80 80 206 2", -" c #725203", -". c #785706", -"X c #7B5907", -"o c #7C5A09", -"O c #7F5F10", -"+ c #815E0B", -"@ c #85620C", -"# c #89650F", -"$ c #856313", -"% c #896614", -"& c #8D6913", -"* c #886718", -"= c #8D6B1B", -"- c #926D14", -"; c #926E1B", -": c #967116", -"> c #997317", -", c #95711E", -"< c #9B7419", -"1 c #9F781B", -"2 c #A27B1D", -"3 c #8F6F22", -"4 c #926F21", -"5 c #947323", -"6 c #9A7623", -"7 c #9D7925", -"8 c #957628", -"9 c #9A7729", -"0 c #9D7B2B", -"q c #9D7F33", -"w c #A47D23", -"e c #A97F27", -"r c #A37E2B", -"t c #9F8030", -"y c #A78021", -"u c #AC8425", -"i c #A5802D", -"p c #AC842B", -"a c #AF8829", -"s c #B2872C", -"d c #B28B2D", -"f c #A68333", -"g c #AA8633", -"h c #AD8A36", -"j c #A4863A", -"k c #A88638", -"l c #A7893B", -"z c #AC8B3B", -"x c #B28732", -"c c #B48C32", -"v c #B98E34", -"b c #B28D3B", -"n c #B88F3C", -"m c #B69033", -"M c #BD9235", -"N c #B4913D", -"B c #BC943A", -"V c #BE993C", -"C c #C19336", -"Z c #C1953B", -"A c #C49A3C", -"S c #C99C3D", -"D c #CDA13F", -"F c #D0A33F", -"G c #A88B40", -"H c #B08F40", -"J c #AE9142", -"K c #AE944C", -"L c #B49443", -"P c #BB9542", -"I c #B49946", -"U c #BD9846", -"Y c #B3964C", -"T c #BB974A", -"R c #B6994A", -"E c #BF9C4A", -"W c #B69B53", -"Q c #B99D53", -"! c #BCA055", -"~ c #BDA25A", -"^ c #C49742", -"/ c #C49C43", -"( c #CB9E42", -") c #C49D4B", -"_ c #C99E4C", -"` c #C29F52", -"' c #C5A244", -"] c #CDA245", -"[ c #C5A34C", -"{ c #CCA34B", -"} c #CCA94D", -"| c #D2A445", -" . c #D1A54B", -".. c #D5AA4E", -"X. c #DBAF4F", -"o. c #C6A352", -"O. c #CBA554", -"+. c #C5AA57", -"@. c #CEAC54", -"#. c #C4A65A", -"$. c #CDA458", -"%. c #C2A85F", -"&. c #CEAA5B", -"*. c #D0A550", -"=. c #D4AB53", -"-. c #DBAE53", -";. c #D0A75B", -":. c #D4AC5A", -">. c #D9AE5C", -",. c #CEB25E", -"<. c #D4B156", -"1. c #DDB156", -"2. c #D4B25C", -"3. c #DCB35D", -"4. c #D7B85C", -"5. c #DCBA5E", -"6. c #E2B355", -"7. c #E2B65B", -"8. c #E4BA5D", -"9. c #EABD5E", -"0. c #C5AA62", -"q. c #CCAE63", -"w. c #C6AE69", -"e. c #D5AF62", -"r. c #CEB167", -"t. c #CCB36C", -"y. c #D5B162", -"u. c #DCB462", -"i. c #D7B964", -"p. c #DCBC64", -"a. c #D2B66B", -"s. c #DCB669", -"d. c #D7BE69", -"f. c #DFB86A", -"g. c #D0B771", -"h. c #D2BA74", -"j. c #D5BE78", -"k. c #E1B766", -"l. c #E4BB63", -"z. c #E9BE63", -"x. c #E3BB6A", -"c. c #E9BF6A", -"v. c #E1BE72", -"b. c #DDC16B", -"n. c #DAC27E", -"m. c #E4C164", -"M. c #ECC264", -"N. c #E4C36B", -"B. c #EBC36C", -"V. c #E7C96F", -"C. c #EECA6E", -"Z. c #F1C564", -"A. c #F1C76A", -"S. c #F5CB6C", -"D. c #FACE6D", -"F. c #F4D06F", -"G. c #FCD06E", -"H. c #E5C371", -"J. c #EDC573", -"K. c #E4CA73", -"L. c #ECCC74", -"P. c #E7CF7A", -"I. c #EBCD7A", -"U. c #F3CD73", -"Y. c #F8CE71", -"T. c #F3CD7A", -"R. c #EDD076", -"E. c #EDD17B", -"W. c #F4D274", -"Q. c #FBD274", -"!. c #FED977", -"~. c #F3D47B", -"^. c #FDD47A", -"/. c #F5DA7C", -"(. c #FDDA7C", -"). c #FFE07F", -"_. c #DBC481", -"`. c #DFC885", -"'. c #E1CA86", -"]. c #EACC80", -"[. c #E4CD8A", -"{. c #EED383", -"}. c #E7D18F", -"|. c #EAD38C", -" X c #F4D680", -".X c #FDD780", -"XX c #F5DA83", -"oX c #FCDC84", -"OX c #F5DB8A", -"+X c #FADE89", -"@X c #EAD492", -"#X c #EED896", -"$X c #EFDA9A", -"%X c #F1DD9D", -"&X c #FDE283", -"*X c #F6E18D", -"=X c #FEE48D", -"-X c #FFE692", -";X c #FFE894", -":X c #FBE799", -">X c #FFEA98", -",X c #F6E2A3", -".J..X.X.X.X(.W.Z.C.&X;X;X;X;X-X-X-X<.u u < 3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3Xu u c oX=X=X=X=X=X=X=Xl.Z C M M C C v v v s w = '.2X2X2X5 $ = 2X2X2X}.5 g ) u./.+X+X=X=X=X&XW.Z.F.=X;X;X;X;X-X-X*XV u y @ X 3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3Xu u u N.-X-X-X-X=X=X=XB.Z M C v v s e e e e w > % `.2X2X2X= + % 2X2X2X}.= r L 4.E.OX+X-X=X=X&X).W.M.R.;X;X;X-X-X-X;XR.u u y 3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3Xu u U -X-X-X-X-X-X=XW.^ C C C x e e r 6 5 4 ; = $ `.2X2X2X= O = 2X2X2X}.O = t Q ,.b.P./.*X=X&X&X).F.M.W.;X;X;X;X&X-X&X} u u O 3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3Xu u u R.-X-X-X-X-X-X=X=.{ ^ Z C x n 2X2X.>.>.=.=._ n b 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X:XI N +.V./.).).F.F.9.W.;X=X;X-X-X-XR.u u > 3X3X3X3X3X3X3X3X", -"3X3X3X3X3Xu u d =X;X-X-X-X-X-Xx.>.>.>.>.>...^ P 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X,Xl N 4.R.!.!.!.G.Z.M.&X;X=X=X-X-X-XB a u 3X3X3X3X3X3X3X", -"3X3X3X3X3Xu u @.;X;X-X;X;X;XXX>.:.>.>.>.>.>._ P ` Y Y W _.2X2X2X2X2X2X@XW W ~ 0.t.'..>.>.>.>.>.>.=._ P z r 4 8 2X2X2X2X2X2X_.. $ , 6 1 3 t ~ 1X2X2X2X2X2X2X2Xt B 5.G.!.!.G.G.M.9.&X;X=X-X-X=X/.u u > 3X3X3X3X3X3X3X", -"3X3X3X3Xu u d =X;X;X=X;X;X=X3.>.>.>.e.>.3.3.>.:.*._ P r 9 2X2X2X2X2X1Xn.@ , c B N m h 8 ~ 2X2X2X2X2X2X2XI h <.F.!.G.G.F.M.9.W.;X=X-X-X=X=Xm u y . 3X3X3X3X3X3X", -"3X3X3X3Xu u ' -X-X>X-X-X-X X>.>.>.>.>.>.>.u.u.u.u.3.$.P f 2X2X2X2X2X2X_.$ i / -.<.8.} h 8 1X2X2X2X2X2X2X! i <.S.G.G.G.G.Z.9.Z.=X-X=X-X&X-X} u u X 3X3X3X3X3X3X", -"3X3X3X3Xu u 4.-X-X-X-X-X-XJ.3.>.>.k.k.k.k.k.u.k.u.u.:.U k 2X2X2X2X2X1X_.% f } 8.Z.F.8.U 8 ,X2X2X2X2X2X2XI g } Z.D.G.D.G.D.Z.9.&X-X=X=X=X-Xm.u u @ 3X3X3X3X3X3X", -"3X3X3X3Xu u K.;X-X;X-X>X-Xk.3.k.k.k.k.k.k.k.k.k.k.u.e.U k 2X2X2X2X2X2X_.% f [ 8.F.M.<.b i 2X2X2X2X2X2X2Xt a X.Z.D.D.D.G.G.Z.9./.=X-X=X=X=XR.u u & 3X3X3X3X3X3X", -"3X3X3X3Xu u E.;X-X;X-X-X=Xl.l.x.c.k.x.k.k.x.x.v.x.x.u.) z 2X2X2X2X2X2X_.$ 7 L <.<.} N 6 h.2X2X2X2X2X2X_.: V 1.S.D.D.G.D.S.M.6.W.-X=X-X=X=X&Xu u > X 3X3X3X3X3X", -"3X3X3Xu a u =X;X;X;X;X;XoX7.z.c.c.c.c.c.c.c.c.c.x.k.u.) z 2X2X2X2X2X2Xn.o = i N h i l n.2X2X2X2X2X2X.o.L r [.2X2X2X9 = 8 2X2X2X}.4 r ^ _ *.*._ ) ) ^ ^ ^ O.oX=X-X-X-X-X-X-X<.u u : . 3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3Xy u u i.=X=X=X=X=X-X*X=XW.9.M.A.B.3.5.5.;.U f [.2X2X2Xq 4 8 2X2X2X}.r q _ _ ;.;.*._ _ ` _ e.+X-X-X-X-X-X-X-XR.a u 2 3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3Xu u u K.=X=X=X-X=X=X=X=XXXz.M.8.5.8.u.:.) h }.2X2X2Xj r f 2X2X2X@Xq T _ e.e.u.e.;.$.$.b.-X-X-X=X;X=X;X-X&Xa a u + 3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3Xu u d ~.=X=X=X=X=X-X=X-X+XC.3.5.7.7.2.@.) q.r.q.q.H H L g.r.w.q.T ` e.k.v.k.k.s.s.{.-X-X;X-X;X;X;X;X*XV u u & . 3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X2 u u c XX-X=X=X=X=X-X=X-X-X Xl.7.7.u.2.$.o.[ [ o.O.$.&.&.` ` ` q.s.k.v.k.k.x.{.%X>X>X>X;X>X;X>X>X*XV u u > 3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X2 u u m ~.=X-X-X-X=X-X-X-X-X-X Xc.7.5.u.3.e.y.u.s.f.k.s.e.e.s.s.k.k.k.v. X:X>X>X>X>X>X>X;X>X>X*XV u u < 3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u d R.-X=X-X=X-X-X-X-X-X-X-X+XI.v.u.s.l.k.k.x.x.x.s.s.s.s.j.].+X>X>X>X>X>X:X>X>X>X>X>XOXV u u 1 3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u a p.-X-X-X;X;X;X-X-X-X:X-X-X-X-XOX XL.J.J.J.L.I.].OX:X>X-X>X>X-X>X>X>X>X>X>X>X>XK.a a u < 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u u @.=X;X;X>X;X-X-X>X-X-X-X-X;X-X-X-X-X-X>X>X-X>X-X>X>X>X>X;X>X>X>X-X>X-X-X:X<.u u u > 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X1 u u u m n.>X;X>X>X-X-X-X-X>X-X-X-X;X;X;X-X-X-X-X-X>X-X-X>X-X>X>X-X>X>X>X>XK.B u u u & 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xw u u u / {.>X>X-X-X-X-X-X-X-X-X-X-X;X-X-X;X:X-X-X>X-X:X>X;X;X>X;X;X{.[ u u u w + 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u u u ) K.-X-X-X-X:X-X-X-X-X-X-X-X-X-X-X-X-X>X-X-X-X-X-X-XE.[ u u u u - . 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X1 u u u u m 2.E.-X+X:X-X-X-X-X-X-X-X-X-X:X-X-X-X;X-XOXi.B u u u u 1 o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X> u u u u u v [ l.I.OX-X-X-X-X-X-X-X-X+XI.f.@.m u u u u u 1 + o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X& 2 u u u u u u u d B V V V V B d u u u u u u u y - . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X+ - 1 u u u u u u u a u u u u u u u u 2 - o o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xo . X # - > 1 2 2 2 1 2 > - # o . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xo o . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", -"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X" -}; diff --git a/share/pixmaps/favicon.ico b/share/pixmaps/favicon.ico index d249e41feb0fd2bb0d0ab942a9c84f304586164a..754eebc48814ff7191543d92207ae881227ef33e 100644 GIT binary patch literal 1150 zcmZ`&ZAe>J7(U{lP|D~JDgD=JKGfP-=5QO^Sl3}KqqQA{!l0}l_@^5qPWEU2+A_-M zkIFJNQ5&sM<5z#gY|dHIub@Ri=cdEil}ciAuQ$0ji803H-dpX{_ZU*7?QVE)?mg#y zo^#LhJcqG7`t9D$=>8VF_y%Kp7-J<=G(;oWar$G7=3c%4ugrl+2xwrfsn`C7}pI=t1vbuV7AJ7ZGXTs`nOoa zdwB25*hC`n=H)*GEAKbiQz*Tmp|p*c3X^ReM&dI3tl-jcz{-2KbEHzKomXxzHyCXx z80{HUbY%47{p;#CZh7saZXE|4D$K1a_`Jay!g2EG`KU1Oe?2mvM+V_?}G7t2o;mx~;@k3LF!W?@C+Jy3s~>TN>y41^nk1pePD1 z{+`Ac14+#IV+aO=I60U>Wv7M%H!?8)64%?wqwk01zWt<;k=EYdnnAfefwKc)NRouk z=~Z-0%81A^+V`zu4|(MUH9pZ2IY(YJ~~P{g7j zqjyTiYa*MKJHTWcL@7FaaZ+fIMlg@(YY`lg?*`3szsGfpe6QmW54g*n2&WFM9;kyF)nA72hmxOK+M8TS|4+8-9@= zj^|nAnY8-C*26B+m^><`zI~09m8NxCTiwb|MTd%??uK8J7m;2t| z?*#^6AV!UXd=JIirvV4xzx#Gr`xKy-W8*Bxr0k?D<9=xy;Jf^0W;_b9jOiwL?%b`lRW>msC-He%;SK*p@4U50HfO#30u;j=^ zDALcvGrI&Uq!d{f;dQhOo;elpJYEi;6H>Y5n44+FyII#T|5!cVIbH`JlUb?;9~c|3 zBJZF07~J7Mlv{u=&&# zgcjD|eNz(_n;Nm?WGfW%?J1?mYsS(q+u(b;5xxbD@F{GAqM!py3%-T-R~_&K(fxzMhgcsMtr|33T6?Y=w+zkX2wIJ|ZGXhK6;9qhJYtDa*)g`yFp|k^=<@b=% z7AP;aV9TXe1Yd5))`|{nueyaW^KFD)y^DxzcMyH_G~&LhM8fHEL|te=blDBWUur@^ zc@xxsZ-VM_GgK8VNUm%_qPZQqs#c^_-$d%QThQ138*#NiAgZj-ams3|E3F8Zh4oUNt|?V+7ps zB7!g$Nf?h@IH3}=(TRnijSuJ;1S;Y{Wg4jYD`+eO&0qf{Zzp*t$uE+;pX5U&ua^Ah zk~c}dQ1TZfFXzdij_pAhNv?Vx6F_8LnUwd57
&NeSIdbJk`}Pf$5i^rN9A~rZH!;sm^il^8K)7nF$NLBL zyAP!PaYCT(S9b5}Hmq2+N&oy5fBooLTGzpU(0MKY_!IrFU)h=R+NAiPfzCQluVqX0 zifH|qiEnQU8ni$+XVxq?{RoGo?Jggv7e5oG+xW(eD7|}xev$8Lt*t%$l7Iig)VTSv z(^s!aP|2iOsM_|s;h&D$_13CwI@?gWz-b8@pLbrL?VYG~eARjb@BK-mO-|N^yky<8 zd@P(l*=b(?Uhf#0XL4UfG6y3E^w* zzp*{-{J4lioi8i3Juj_GXntYU&SUlg(QZGNT%k7(oD!8DwkYG=_wueYsrdnuTS;we zALU)8kFkQbfr%X99hyHQL~Z-iK5NqQ20471c|>?2Jfpa&?-l<@7l)|q z_?YWm6s}QNOW`qvF%-5?IK_;nZXRjtp|F|G=~Wa~GD+@HTqW1AeXU z6sJ*`N?{(wUlczv@?TvHDr@H8W!vs8J%0Iz@*Z;i;s=U9taT#6^?Zz!WUgW_HKo^7W%jM3M-DZZdhK*GJ(*T>ph=D-xyiR{?AZtkqP zL-9OiJwb60WevgP%2tY>`Qe$H6mL<}W;ypM4qqM`WyxB$2@wZJ&PdL$h>_m$H+m^f zrFfgNPLStRL-8!dO;k5MpsWcv+;>Ojf~eGi{ptQsr(NkblXn}Ai(h3PKVV{W9}{JK zfAvw^Nv9;!cXk_8o805lgb4qCn-ZBmcWS&L(=ENYVNv#l9=Fd+zI#h!Dsl+@bI|y$ h`z=ea|Jgc68s-!YGR%n_&|iRI&M(!&ah8lF`yZ|pi&Ovr From a824121eb8458350a2c4f7c64601a9d1b41425c9 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Thu, 16 May 2013 13:27:21 -0700 Subject: [PATCH 39/69] It's after 2013-05-15 forever now, so remove the code for the May 15 fork. --- contrib/test-patches/temp-revert-1.patch | 21 ----- contrib/test-patches/temp-revert-3.patch | 34 ------- contrib/test-patches/temp-revert-4.patch | 110 ----------------------- src/main.cpp | 23 ----- src/test/checkblock_tests.cpp | 2 - 5 files changed, 190 deletions(-) delete mode 100644 contrib/test-patches/temp-revert-1.patch delete mode 100644 contrib/test-patches/temp-revert-3.patch delete mode 100644 contrib/test-patches/temp-revert-4.patch diff --git a/contrib/test-patches/temp-revert-1.patch b/contrib/test-patches/temp-revert-1.patch deleted file mode 100644 index a5aec641c..000000000 --- a/contrib/test-patches/temp-revert-1.patch +++ /dev/null @@ -1,21 +0,0 @@ -commit 4dcc8701ac0eb09d8992d19fb411cee3c9aaf394 -Author: Matt Corallo -Date: Sun Mar 24 20:45:44 2013 -0400 - - Revert "Update unit test to match rule enforcement starts 21 March" - - This reverts commit d3e8c6a9d3fad68b0eee4434401ec7b3066399a2. - -diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp -index 3cfb6db..e167def 100644 ---- a/src/test/checkblock_tests.cpp -+++ b/src/test/checkblock_tests.cpp -@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(May15) - if (read_block("Mar12Fork.dat", forkingBlock)) - { - CValidationState state; -- forkingBlock.nTime = tMay15-1; // Invalidates PoW -+ BOOST_CHECK(!forkingBlock.CheckBlock(state, true, true)); - BOOST_CHECK(!forkingBlock.CheckBlock(state, false, false)); - - // After May 15'th, big blocks are OK: diff --git a/contrib/test-patches/temp-revert-3.patch b/contrib/test-patches/temp-revert-3.patch deleted file mode 100644 index 5c0775dfa..000000000 --- a/contrib/test-patches/temp-revert-3.patch +++ /dev/null @@ -1,34 +0,0 @@ -commit ba84709c65b911798ddae1285d807f4cd036990d -Author: Matt Corallo -Date: Sun Mar 24 20:45:56 2013 -0400 - - Revert "Before 15 May, limit created block size to 500K" - - This reverts commit 402f19b64530775a7e4ded025c80d8c16a55e454. - -diff --git a/src/main.cpp b/src/main.cpp -index 22baf0f..51ada0a 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -2057,8 +2057,8 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk - return state.DoS(100, error("CheckBlock() : size limits failed")); - - // Special short-term limits to avoid 10,000 BDB lock limit: -- if (GetBlockTime() >= 1363867200 && // start enforcing 21 March 2013, noon GMT -- GetBlockTime() < 1368576000) // stop enforcing 15 May 2013 00:00:00 -+ if (GetBlockTime() > 1363039171 && // 11 March 2013, timestamp of block before the big fork -+ GetBlockTime() < 1368576000) // 15 May 2013 00:00:00 - { - // Rule is: #unique txids referenced <= 4,500 - // ... to prevent 10,000 BDB lock exhaustion on old clients -@@ -4155,10 +4155,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) - // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); - -- // Special compatibility rule before 15 May: limit size to 500,000 bytes: -- if (GetAdjustedTime() < 1368576000) -- nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN)); -- - // How much of the block should be dedicated to high-priority transactions, - // included regardless of the fees they pay - unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); diff --git a/contrib/test-patches/temp-revert-4.patch b/contrib/test-patches/temp-revert-4.patch deleted file mode 100644 index f93d7549c..000000000 --- a/contrib/test-patches/temp-revert-4.patch +++ /dev/null @@ -1,110 +0,0 @@ -commit ca96b88b61f647d4f56d5d06321dda08a43bf92f -Author: Matt Corallo -Date: Sun Mar 24 20:46:01 2013 -0400 - - Revert "CheckBlock rule until 15-May for 10,000 BDB lock compatibility" - - This reverts commit 8c222dca4f961ad13ec64d690134a40d09b20813. - -diff --git a/src/main.cpp b/src/main.cpp -index 51ada0a..9a06dbf 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -2056,25 +2056,6 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, error("CheckBlock() : size limits failed")); - -- // Special short-term limits to avoid 10,000 BDB lock limit: -- if (GetBlockTime() > 1363039171 && // 11 March 2013, timestamp of block before the big fork -- GetBlockTime() < 1368576000) // 15 May 2013 00:00:00 -- { -- // Rule is: #unique txids referenced <= 4,500 -- // ... to prevent 10,000 BDB lock exhaustion on old clients -- set setTxIn; -- for (size_t i = 0; i < vtx.size(); i++) -- { -- setTxIn.insert(vtx[i].GetHash()); -- if (i == 0) continue; // skip coinbase txin -- BOOST_FOREACH(const CTxIn& txin, vtx[i].vin) -- setTxIn.insert(txin.prevout.hash); -- } -- size_t nTxids = setTxIn.size(); -- if (nTxids > 4500) -- return error("CheckBlock() : 15 May maxlocks violation"); -- } -- - // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) - return state.DoS(50, error("CheckBlock() : proof of work failed")); -diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp -deleted file mode 100644 -index e167def..0000000 ---- a/src/test/checkblock_tests.cpp -+++ /dev/null -@@ -1,66 +0,0 @@ --// --// Unit tests for block.CheckBlock() --// --#include -- --#include // for 'map_list_of()' --#include --#include --#include -- --#include "main.h" --#include "wallet.h" --#include "net.h" --#include "util.h" -- --BOOST_AUTO_TEST_SUITE(CheckBlock_tests) -- --bool --read_block(const std::string& filename, CBlock& block) --{ -- namespace fs = boost::filesystem; -- fs::path testFile = fs::current_path() / "test" / "data" / filename; --#ifdef TEST_DATA_DIR -- if (!fs::exists(testFile)) -- { -- testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; -- } --#endif -- FILE* fp = fopen(testFile.string().c_str(), "rb"); -- if (!fp) return false; -- -- fseek(fp, 8, SEEK_SET); // skip msgheader/size -- -- CAutoFile filein = CAutoFile(fp, SER_DISK, CLIENT_VERSION); -- if (!filein) return false; -- -- filein >> block; -- -- return true; --} -- --BOOST_AUTO_TEST_CASE(May15) --{ -- // Putting a 1MB binary file in the git repository is not a great -- // idea, so this test is only run if you manually download -- // test/data/Mar12Fork.dat from -- // http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/Mar12Fork.dat/download -- unsigned int tMay15 = 1368576000; -- SetMockTime(tMay15); // Test as if it was right at May 15 -- -- CBlock forkingBlock; -- if (read_block("Mar12Fork.dat", forkingBlock)) -- { -- CValidationState state; -- BOOST_CHECK(!forkingBlock.CheckBlock(state, true, true)); -- BOOST_CHECK(!forkingBlock.CheckBlock(state, false, false)); -- -- // After May 15'th, big blocks are OK: -- forkingBlock.nTime = tMay15; // Invalidates PoW -- BOOST_CHECK(forkingBlock.CheckBlock(state, false, false)); -- } -- -- SetMockTime(0); --} -- --BOOST_AUTO_TEST_SUITE_END() diff --git a/src/main.cpp b/src/main.cpp index e2bed5278..056020895 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2076,25 +2076,6 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed")); - // Special short-term limits to avoid 10,000 BDB lock limit: - if (GetBlockTime() >= 1363867200 && // start enforcing 21 March 2013, noon GMT - GetBlockTime() < 1368576000) // stop enforcing 15 May 2013 00:00:00 - { - // Rule is: #unique txids referenced <= 4,500 - // ... to prevent 10,000 BDB lock exhaustion on old clients - set setTxIn; - for (size_t i = 0; i < vtx.size(); i++) - { - setTxIn.insert(vtx[i].GetHash()); - if (i == 0) continue; // skip coinbase txin - BOOST_FOREACH(const CTxIn& txin, vtx[i].vin) - setTxIn.insert(txin.prevout.hash); - } - size_t nTxids = setTxIn.size(); - if (nTxids > 4500) - return error("CheckBlock() : 15 May maxlocks violation"); - } - // Check proof of work matches claimed amount if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) return state.DoS(50, error("CheckBlock() : proof of work failed")); @@ -4191,10 +4172,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); - // Special compatibility rule before 15 May: limit size to 500,000 bytes: - if (GetAdjustedTime() < 1368576000) - nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN)); - // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 3cfb6dbfa..d626f9a6f 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -52,8 +52,6 @@ BOOST_AUTO_TEST_CASE(May15) if (read_block("Mar12Fork.dat", forkingBlock)) { CValidationState state; - forkingBlock.nTime = tMay15-1; // Invalidates PoW - BOOST_CHECK(!forkingBlock.CheckBlock(state, false, false)); // After May 15'th, big blocks are OK: forkingBlock.nTime = tMay15; // Invalidates PoW From 38a33c085eb303753de14feef4e63b07a3b8e5f9 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Mon, 13 May 2013 08:52:54 +0200 Subject: [PATCH 40/69] translations update 2013-05-19 (for 0.8.2 release) - integrates current translations from Transifex - new translation: af_ZA --- src/qt/bitcoin.qrc | 1 + src/qt/locale/bitcoin_af_ZA.ts | 2917 ++++++++++++++++++++++++++++++++ src/qt/locale/bitcoin_de.ts | 2 +- src/qt/locale/bitcoin_el_GR.ts | 395 +++-- src/qt/locale/bitcoin_es.ts | 24 +- src/qt/locale/bitcoin_ja.ts | 102 +- src/qt/locale/bitcoin_la.ts | 24 +- src/qt/locale/bitcoin_nl.ts | 12 +- src/qt/locale/bitcoin_pt_BR.ts | 8 +- src/qt/locale/bitcoin_pt_PT.ts | 12 +- src/qt/locale/bitcoin_sk.ts | 56 +- src/qt/locale/bitcoin_zh_TW.ts | 2 +- 12 files changed, 3247 insertions(+), 308 deletions(-) create mode 100644 src/qt/locale/bitcoin_af_ZA.ts diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 0ec90a294..c2f830852 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -50,6 +50,7 @@ res/movies/update_spinner.mng + locale/bitcoin_af_ZA.qm locale/bitcoin_ar.qm locale/bitcoin_bg.qm locale/bitcoin_bs.ts diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts new file mode 100644 index 000000000..029b91a7a --- /dev/null +++ b/src/qt/locale/bitcoin_af_ZA.ts @@ -0,0 +1,2917 @@ + +UTF-8 + + AboutDialog + + + About Bitcoin + + + + + <b>Bitcoin</b> version + <b>Bitcoin</b> weergawe + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + + Copyright + + + + + The Bitcoin developers + + + + + AddressBookPage + + + Address Book + Adres Boek + + + + Double-click to edit address or label + Dubbel-klik om die adres of etiket te wysig + + + + Create a new address + Skep 'n nuwe adres + + + + Copy the currently selected address to the system clipboard + Maak 'n kopie van die huidige adres na die stelsel klipbord + + + + &New Address + + + + + These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + + &Copy Address + + + + + Show &QR Code + + + + + Sign a message to prove you own a Bitcoin address + + + + + Sign &Message + Teken &Boodskap + + + + Delete the currently selected address from the list + + + + + Export the data in the current tab to a file + + + + + &Export + + + + + Verify a message to ensure it was signed with a specified Bitcoin address + + + + + &Verify Message + + + + + &Delete + &Verwyder + + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + + + + + Copy &Label + + + + + &Edit + + + + + Send &Coins + Stuur &Muntstukke + + + + Export Address Book Data + Voer die Adresboek Data Uit + + + + Comma separated file (*.csv) + + + + + Error exporting + Fout uitvoering + + + + Could not write to file %1. + Kon nie na die %1 lêer skryf nie + + + + AddressTableModel + + + Label + Etiket + + + + Address + Adres + + + + (no label) + (geen etiket) + + + + AskPassphraseDialog + + + Passphrase Dialog + + + + + Enter passphrase + Tik Wagwoord in + + + + New passphrase + Nuwe wagwoord + + + + Repeat new passphrase + Herhaal nuwe wagwoord + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Tik die nuwe wagwoord vir die beursie in.<br/>Gebruik asseblief 'n wagwoord van <b>ten minste 10 ewekansige karakters</b>, of <b>agt (8) of meer woorde.</b> + + + + Encrypt wallet + Enkripteer beursie + + + + This operation needs your wallet passphrase to unlock the wallet. + Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit. + + + + Unlock wallet + Sluit beursie oop + + + + This operation needs your wallet passphrase to decrypt the wallet. + Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit. + + + + Decrypt wallet + Sluit beursie oop + + + + Change passphrase + Verander wagwoord + + + + Enter the old and new passphrase to the wallet. + Tik asseblief die ou en nuwe wagwoord vir die beursie in. + + + + Confirm wallet encryption + Bevestig beursie enkripsie. + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + + + + + Are you sure you wish to encrypt your wallet? + + + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + + + + + + Warning: The Caps Lock key is on! + + + + + + Wallet encrypted + Die beursie is nou bewaak + + + + Bitcoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + + + + + + + + Wallet encryption failed + Die beursie kon nie bewaak word nie + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Beursie bewaaking het misluk as gevolg van 'n interne fout. Die beursie is nie bewaak nie! + + + + + The supplied passphrases do not match. + Die wagwoord stem nie ooreen nie + + + + Wallet unlock failed + Beursie oopsluiting het misluk + + + + + + The passphrase entered for the wallet decryption was incorrect. + Die wagwoord wat ingetik was om die beursie oop te sluit, was verkeerd. + + + + Wallet decryption failed + Beursie dekripsie het misluk + + + + Wallet passphrase was successfully changed. + + + + + BitcoinGUI + + + Sign &message... + + + + + Synchronizing with network... + Sinchroniseer met die netwerk ... + + + + &Overview + &Oorsig + + + + Show general overview of wallet + Wys algemene oorsig van die beursie + + + + &Transactions + &Transaksies + + + + Browse transaction history + Besoek transaksie geskiedenis + + + + Edit the list of stored addresses and labels + Wysig die lys van gestoorde adresse en etikette + + + + Show the list of addresses for receiving payments + Wys die lys van adresse vir die ontvangs van betalings + + + + E&xit + S&luit af + + + + Quit application + Sluit af + + + + Show information about Bitcoin + Wys inligting oor Bitcoin + + + + About &Qt + + + + + Show information about Qt + + + + + &Options... + &Opsies + + + + &Encrypt Wallet... + + + + + &Backup Wallet... + + + + + &Change Passphrase... + + + + + Importing blocks from disk... + + + + + Reindexing blocks on disk... + + + + + Send coins to a Bitcoin address + + + + + Modify configuration options for Bitcoin + + + + + Backup wallet to another location + + + + + Change the passphrase used for wallet encryption + + + + + &Debug window + + + + + Open debugging and diagnostic console + + + + + &Verify message... + + + + + + Bitcoin + Bitcoin + + + + Wallet + Beursie + + + + &Send + + + + + &Receive + + + + + &Addresses + + + + + &About Bitcoin + + + + + &Show / Hide + + + + + Show or hide the main Window + + + + + Encrypt the private keys that belong to your wallet + + + + + Sign messages with your Bitcoin addresses to prove you own them + + + + + Verify messages to ensure they were signed with specified Bitcoin addresses + + + + + &File + &Lêer + + + + &Settings + &Instellings + + + + &Help + &Hulp + + + + Tabs toolbar + Blad nutsbalk + + + + + [testnet] + + + + + Bitcoin client + + + + + %n active connection(s) to Bitcoin network + + + + + No block source available... + + + + + Processed %1 of %2 (estimated) blocks of transaction history. + + + + + Processed %1 blocks of transaction history. + + + + + %n hour(s) + + + + + %n day(s) + + + + + %n week(s) + + + + + %1 behind + %1 agter + + + + Last received block was generated %1 ago. + Ontvangs van laaste blok is %1 terug. + + + + Transactions after this will not yet be visible. + + + + + Error + Fout + + + + Warning + + + + + Information + Informasie + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Up to date + + + + + Catching up... + + + + + Confirm transaction fee + + + + + Sent transaction + + + + + Incoming transaction + + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + + URI handling + + + + + + URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + + A fatal error occurred. Bitcoin can no longer continue safely and will quit. + + + + + ClientModel + + + Network Alert + + + + + EditAddressDialog + + + Edit Address + + + + + &Label + + + + + The label associated with this address book entry + + + + + &Address + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + New receiving address + + + + + New sending address + + + + + Edit receiving address + + + + + Edit sending address + + + + + The entered address "%1" is already in the address book. + + + + + The entered address "%1" is not a valid Bitcoin address. + + + + + Could not unlock wallet. + + + + + New key generation failed. + + + + + GUIUtil::HelpMessageBox + + + + Bitcoin-Qt + + + + + version + + + + + Usage: + Gebruik: + + + + command-line options + + + + + UI options + + + + + Set language, for example "de_DE" (default: system locale) + + + + + Start minimized + + + + + Show splash screen on startup (default: 1) + + + + + OptionsDialog + + + Options + + + + + &Main + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. + + + + + Pay transaction &fee + + + + + Automatically start Bitcoin after logging in to the system. + + + + + &Start Bitcoin on system login + + + + + Reset all client options to default. + + + + + &Reset Options + + + + + &Network + + + + + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + + + + + Connect to the Bitcoin network through a SOCKS proxy (e.g. when connecting through Tor). + + + + + &Connect through SOCKS proxy: + + + + + Proxy &IP: + + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + &Port: + + + + + Port of the proxy (e.g. 9050) + + + + + SOCKS &Version: + + + + + SOCKS version of the proxy (e.g. 5) + + + + + &Window + + + + + Show only a tray icon after minimizing the window. + + + + + &Minimize to the tray instead of the taskbar + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + + M&inimize on close + + + + + &Display + + + + + User Interface &language: + + + + + The user interface language can be set here. This setting will take effect after restarting Bitcoin. + + + + + &Unit to show amounts in: + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + Whether to show Bitcoin addresses in the transaction list or not. + + + + + &Display addresses in transaction list + + + + + &OK + + + + + &Cancel + + + + + &Apply + + + + + default + + + + + Confirm options reset + + + + + Some settings may require a client restart to take effect. + + + + + Do you want to proceed? + + + + + + Warning + + + + + + This setting will take effect after restarting Bitcoin. + + + + + The supplied proxy address is invalid. + + + + + OverviewPage + + + Form + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. + + + + + Balance: + + + + + Unconfirmed: + + + + + Wallet + Beursie + + + + Immature: + + + + + Mined balance that has not yet matured + + + + + <b>Recent transactions</b> + + + + + Your current balance + + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + + + out of sync + + + + + PaymentServer + + + Cannot start bitcoin: click-to-pay handler + + + + + QRCodeDialog + + + QR Code Dialog + + + + + Request Payment + + + + + Amount: + + + + + Label: + + + + + Message: + + + + + &Save As... + + + + + Error encoding URI into QR Code. + + + + + The entered amount is invalid, please check. + + + + + Resulting URI too long, try to reduce the text for label / message. + + + + + Save QR Code + + + + + PNG Images (*.png) + + + + + RPCConsole + + + Client name + + + + + + + + + + + + + + N/A + + + + + Client version + + + + + &Information + + + + + Using OpenSSL version + + + + + Startup time + + + + + Network + + + + + Number of connections + + + + + On testnet + + + + + Block chain + + + + + Current number of blocks + + + + + Estimated total blocks + + + + + Last block time + + + + + &Open + + + + + Command-line options + + + + + Show the Bitcoin-Qt help message to get a list with possible Bitcoin command-line options. + + + + + &Show + + + + + &Console + + + + + Build date + + + + + Bitcoin - Debug window + + + + + Bitcoin Core + + + + + Debug log file + + + + + Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files. + + + + + Clear console + + + + + Welcome to the Bitcoin RPC console. + + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + + Type <b>help</b> for an overview of available commands. + + + + + SendCoinsDialog + + + + + + + + + + Send Coins + + + + + Send to multiple recipients at once + + + + + Add &Recipient + + + + + Remove all transaction fields + + + + + Clear &All + + + + + Balance: + + + + + 123.456 BTC + + + + + Confirm the send action + + + + + S&end + S&tuur + + + + <b>%1</b> to %2 (%3) + + + + + Confirm send coins + + + + + Are you sure you want to send %1? + + + + + and + + + + + The recipient address is not valid, please recheck. + + + + + The amount to pay must be larger than 0. + + + + + The amount exceeds your balance. + + + + + The total exceeds your balance when the %1 transaction fee is included. + + + + + Duplicate address found, can only send to each address once per send operation. + + + + + Error: Transaction creation failed! + + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + SendCoinsEntry + + + Form + + + + + A&mount: + + + + + Pay &To: + + + + + The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + Die adres waarheen die betaling gestuur moet word (b.v. 1H7wyVL5HCNoVFyyBJSDojwyxcCChU7TPA) + + + + + Enter a label for this address to add it to your address book + + + + + &Label: + + + + + Choose address from address book + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Remove this recipient + + + + + Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Teken boodskap + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + + The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + + + + + Choose an address from the address book + + + + + + Alt+A + + + + + Paste address from clipboard + + + + + Alt+P + + + + + Enter the message you want to sign here + + + + + Signature + Handtekening + + + + Copy the current signature to the system clipboard + + + + + Sign the message to prove you own this Bitcoin address + + + + + Sign &Message + Teken &Boodskap + + + + Reset all sign message fields + + + + + + Clear &All + + + + + &Verify Message + + + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + + + + + The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + + + + Verify the message to ensure it was signed with the specified Bitcoin address + + + + + Verify &Message + + + + + Reset all verify message fields + + + + + + Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) + + + + + Click "Sign Message" to generate signature + + + + + Enter Bitcoin signature + + + + + + The entered address is invalid. + + + + + + + + Please check the address and try again. + + + + + + The entered address does not refer to a key. + + + + + Wallet unlock was cancelled. + + + + + Private key for the entered address is not available. + + + + + Message signing failed. + + + + + Message signed. + + + + + The signature could not be decoded. + + + + + + Please check the signature and try again. + + + + + The signature did not match the message digest. + + + + + Message verification failed. + + + + + Message verified. + + + + + SplashScreen + + + The Bitcoin developers + + + + + [testnet] + + + + + TransactionDesc + + + Open until %1 + + + + + %1/offline + + + + + %1/unconfirmed + + + + + %1 confirmations + + + + + Status + + + + + , broadcast through %n node(s) + + + + + Date + Datum + + + + Source + + + + + Generated + + + + + + From + Van + + + + + + To + Na + + + + + own address + eie adres + + + + label + etiket + + + + + + + + Credit + Krediet + + + + matures in %n more block(s) + + + + + not accepted + nie aanvaar nie + + + + + + + Debit + Debiet + + + + Transaction fee + Transaksie fooi + + + + Net amount + Netto bedrag + + + + Message + Boodskap + + + + Comment + + + + + Transaction ID + Transaksie ID + + + + Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + + + + + Debug information + + + + + Transaction + + + + + Inputs + + + + + Amount + Bedrag + + + + true + waar + + + + false + onwaar + + + + , has not been successfully broadcast yet + + + + + Open for %n more block(s) + + + + + unknown + + + + + TransactionDescDialog + + + Transaction details + + + + + This pane shows a detailed description of the transaction + + + + + TransactionTableModel + + + Date + Datum + + + + Type + Tipe + + + + Address + Adres + + + + Amount + Bedrag + + + + Open for %n more block(s) + + + + + Open until %1 + + + + + Offline (%1 confirmations) + + + + + Unconfirmed (%1 of %2 confirmations) + + + + + Confirmed (%1 confirmations) + + + + + Mined balance will be available when it matures in %n more block(s) + + + + + This block was not received by any other nodes and will probably not be accepted! + + + + + Generated but not accepted + + + + + Received with + Ontvang met + + + + Received from + + + + + Sent to + Gestuur na + + + + Payment to yourself + + + + + Mined + Gemyn + + + + (n/a) + (n.v.t) + + + + Transaction status. Hover over this field to show number of confirmations. + + + + + Date and time that the transaction was received. + Datum en tyd wat die transaksie ontvang was. + + + + Type of transaction. + Tipe transaksie. + + + + Destination address of transaction. + + + + + Amount removed from or added to balance. + + + + + TransactionView + + + + All + Alles + + + + Today + Vandag + + + + This week + Hierdie week + + + + This month + Hierdie maand + + + + Last month + Verlede maand + + + + This year + Hierdie jaar + + + + Range... + + + + + Received with + Ontvang met + + + + Sent to + Gestuur na + + + + To yourself + Aan/na jouself + + + + Mined + Gemyn + + + + Other + Ander + + + + Enter address or label to search + + + + + Min amount + Min bedrag + + + + Copy address + Maak kopie van adres + + + + Copy label + + + + + Copy amount + + + + + Copy transaction ID + + + + + Edit label + + + + + Show transaction details + + + + + Export Transaction Data + + + + + Comma separated file (*.csv) + + + + + Confirmed + + + + + Date + Datum + + + + Type + Tipe + + + + Label + Etiket + + + + Address + Adres + + + + Amount + Bedrag + + + + ID + ID + + + + Error exporting + Fout uitvoering + + + + Could not write to file %1. + Kon nie na die %1 lêer skryf nie + + + + Range: + + + + + to + + + + + WalletModel + + + Send Coins + + + + + WalletView + + + &Export + + + + + Export the data in the current tab to a file + + + + + Backup Wallet + + + + + Wallet Data (*.dat) + + + + + Backup Failed + + + + + There was an error trying to save the wallet data to the new location. + + + + + Backup Successful + + + + + The wallet data was successfully saved to the new location. + + + + + bitcoin-core + + + Bitcoin version + Bitcoin weergawe + + + + Usage: + Gebruik: + + + + Send command to -server or bitcoind + + + + + List commands + + + + + Get help for a command + + + + + Options: + + + + + Specify configuration file (default: bitcoin.conf) + + + + + Specify pid file (default: bitcoind.pid) + + + + + Specify data directory + + + + + Set database cache size in megabytes (default: 25) + + + + + Listen for connections on <port> (default: 8333 or testnet: 18333) + + + + + Maintain at most <n> connections to peers (default: 125) + + + + + Connect to a node to retrieve peer addresses, and disconnect + + + + + Specify your own public address + + + + + Threshold for disconnecting misbehaving peers (default: 100) + + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332) + + + + + Accept command line and JSON-RPC commands + + + + + Run in the background as a daemon and accept commands + + + + + Use the test network + + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com + + + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + + + + + Cannot obtain a lock on data directory %s. Bitcoin is probably already running. + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + + + + + Execute command when a relevant alert is received (%s in cmd is replaced by message) + + + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly. + + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + + Attempt to recover private keys from a corrupt wallet.dat + + + + + Block creation options: + + + + + Connect only to the specified node(s) + + + + + Corrupted block database detected + + + + + Discover own IP address (default: 1 when listening and no -externalip) + + + + + Do you want to rebuild the block database now? + + + + + Error initializing block database + + + + + Error initializing wallet database environment %s! + + + + + Error loading block database + + + + + Error opening block database + + + + + Error: Disk space is low! + Fout: Hardeskyf spasie is baie laag! + + + + Error: Wallet locked, unable to create transaction! + + + + + Error: system error: + + + + + Failed to listen on any port. Use -listen=0 if you want this. + + + + + Failed to read block info + + + + + Failed to read block + + + + + Failed to sync block index + + + + + Failed to write block index + + + + + Failed to write block info + + + + + Failed to write block + + + + + Failed to write file info + + + + + Failed to write to coin database + + + + + Failed to write transaction index + + + + + Failed to write undo data + + + + + Find peers using DNS lookup (default: 1 unless -connect) + + + + + Generate coins (default: 0) + + + + + How many blocks to check at startup (default: 288, 0 = all) + + + + + How thorough the block verification is (0-4, default: 3) + + + + + Not enough file descriptors available. + + + + + Rebuild block chain index from current blk000??.dat files + + + + + Set the number of threads to service RPC calls (default: 4) + + + + + Verifying blocks... + + + + + Verifying wallet... + + + + + Imports blocks from external blk000??.dat file + + + + + Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) + + + + + Information + Informasie + + + + Invalid -tor address: '%s' + + + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + + + + + Invalid amount for -mintxfee=<amount>: '%s' + + + + + Maintain a full transaction index (default: 0) + + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + + Only accept block chain matching built-in checkpoints (default: 1) + + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + + Output extra debugging information. Implies all other -debug* options + + + + + Output extra network debugging information + + + + + Prepend debug output with timestamp + + + + + SSL options: (see the Bitcoin Wiki for SSL setup instructions) + + + + + Select the version of socks proxy to use (4-5, default: 5) + + + + + Send trace/debug info to console instead of debug.log file + + + + + Send trace/debug info to debugger + + + + + Set maximum block size in bytes (default: 250000) + + + + + Set minimum block size in bytes (default: 0) + + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + + Signing transaction failed + + + + + Specify connection timeout in milliseconds (default: 5000) + + + + + System error: + Sisteem fout: + + + + Transaction amount too small + + + + + Transaction amounts must be positive + + + + + Transaction too large + + + + + Use UPnP to map the listening port (default: 0) + + + + + Use UPnP to map the listening port (default: 1 when listening) + + + + + Use proxy to reach tor hidden services (default: same as -proxy) + + + + + Username for JSON-RPC connections + + + + + Warning + + + + + Warning: This version is obsolete, upgrade required! + + + + + You need to rebuild the databases using -reindex to change -txindex + + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + + + + + Allow JSON-RPC connections from specified IP address + + + + + Send commands to node running on <ip> (default: 127.0.0.1) + + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + + Upgrade wallet to latest format + + + + + Set key pool size to <n> (default: 100) + + + + + Rescan the block chain for missing wallet transactions + + + + + Use OpenSSL (https) for JSON-RPC connections + + + + + Server certificate file (default: server.cert) + + + + + Server private key (default: server.pem) + + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + + This help message + + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + + Connect through socks proxy + + + + + Allow DNS lookups for -addnode, -seednode and -connect + + + + + Loading addresses... + Laai adresse... + + + + Error loading wallet.dat: Wallet corrupted + + + + + Error loading wallet.dat: Wallet requires newer version of Bitcoin + + + + + Wallet needed to be rewritten: restart Bitcoin to complete + + + + + Error loading wallet.dat + + + + + Invalid -proxy address: '%s' + + + + + Unknown network specified in -onlynet: '%s' + + + + + Unknown -socks proxy version requested: %i + + + + + Cannot resolve -bind address: '%s' + + + + + Cannot resolve -externalip address: '%s' + + + + + Invalid amount for -paytxfee=<amount>: '%s' + + + + + Invalid amount + + + + + Insufficient funds + + + + + Loading block index... + Laai blok indeks... + + + + Add a node to connect to and attempt to keep the connection open + + + + + Unable to bind to %s on this computer. Bitcoin is probably already running. + + + + + Fee per KB to add to transactions you send + + + + + Loading wallet... + Laai beursie... + + + + Cannot downgrade wallet + + + + + Cannot write default address + + + + + Rescanning... + + + + + Done loading + Klaar gelaai + + + + To use the %s option + + + + + Error + Fout + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 5d857ee6f..ac9db97fe 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -2722,7 +2722,7 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@f You need to rebuild the databases using -reindex to change -txindex - Sie müssen die Datenbanken mit Hilfe von -reindex neu aufbauen, um -txindex verändern zu können. + Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um -txindex zu verändern. diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 9d197f58e..22125e2bb 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -20,17 +20,22 @@ This is experimental software. Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. - + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. Copyright - + Πνευματική ιδιοκτησία The Bitcoin developers - + Οι Bitcoin προγραμματιστές @@ -88,7 +93,7 @@ This product includes software developed by the OpenSSL Project for use in the O Delete the currently selected address from the list - + Αντιγραφη της επιλεγμενης διεύθυνσης στο πρόχειρο του συστηματος @@ -98,7 +103,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Export - + &Εξαγωγή @@ -118,7 +123,7 @@ This product includes software developed by the OpenSSL Project for use in the O These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - + Αυτές είναι οι Bitcoin διευθύνσεις σας για να λαμβάνετε πληρωμές. Δίνοντας μία ξεχωριστή διεύθυνση σε κάθε αποστολέα, θα μπορείτε να ελέγχετε ποιος σας πληρώνει. @@ -133,7 +138,7 @@ This product includes software developed by the OpenSSL Project for use in the O Send &Coins - + Αποστολή νομισμάτων @@ -179,7 +184,7 @@ This product includes software developed by the OpenSSL Project for use in the O Passphrase Dialog - + Φράση πρόσβασης @@ -244,23 +249,24 @@ This product includes software developed by the OpenSSL Project for use in the O Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! - + Προσοχη: Εαν κρυπτογραφησεις το πορτοφολι σου και χάσεις τον κωδικο σου θα χάσεις <b> ΟΛΑ ΣΟΥ ΤΑ BITCOINS</b>! +Είσαι σίγουρος ότι θέλεις να κρυπτογραφησεις το πορτοφολι; Are you sure you wish to encrypt your wallet? - + Είστε σίγουροι ότι θέλετε να κρυπτογραφήσετε το πορτοφόλι σας; IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. - + ΣΗΜΑΝΤΙΚΟ: Τα προηγούμενα αντίγραφα ασφαλείας που έχετε κάνει από το αρχείο του πορτοφόλιου σας θα πρέπει να αντικατασταθουν με το νέο που δημιουργείται, κρυπτογραφημένο αρχείο πορτοφόλιου. Για λόγους ασφαλείας, τα προηγούμενα αντίγραφα ασφαλείας του μη κρυπτογραφημένου αρχείου πορτοφόλιου θα καταστουν άχρηστα μόλις αρχίσετε να χρησιμοποιείτε το νέο κρυπτογραφημένο πορτοφόλι. Warning: The Caps Lock key is on! - + Προσοχη: το πλήκτρο Caps Lock είναι ενεργο. @@ -312,7 +318,7 @@ This product includes software developed by the OpenSSL Project for use in the O Wallet passphrase was successfully changed. - + Ο κωδικος του πορτοφολιού άλλαξε με επιτυχία. @@ -405,12 +411,12 @@ This product includes software developed by the OpenSSL Project for use in the O Importing blocks from disk... - + Εισαγωγή μπλοκ από τον σκληρο δίσκο ... Reindexing blocks on disk... - + Φόρτωση ευρετηρίου μπλοκ στον σκληρο δισκο... @@ -420,7 +426,7 @@ This product includes software developed by the OpenSSL Project for use in the O Modify configuration options for Bitcoin - + Επεργασία ρυθμισεων επιλογών για το Bitcoin @@ -461,17 +467,17 @@ This product includes software developed by the OpenSSL Project for use in the O &Send - + &Αποστολή &Receive - + &Παραλαβή &Addresses - + &Διεύθυνσεις @@ -486,22 +492,22 @@ This product includes software developed by the OpenSSL Project for use in the O Show or hide the main Window - + Εμφάνιση ή αποκρύψη του κεντρικου παράθυρου Encrypt the private keys that belong to your wallet - + Κρυπτογραφήστε τα ιδιωτικά κλειδιά που ανήκουν στο πορτοφόλι σας Sign messages with your Bitcoin addresses to prove you own them - + Υπογράψτε ένα μήνυμα για να βεβαιώσετε πως είστε ο κάτοχος αυτής της διεύθυνσης Verify messages to ensure they were signed with specified Bitcoin addresses - + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως ανήκει μια συγκεκριμένη διεύθυνση Bitcoin @@ -542,47 +548,47 @@ This product includes software developed by the OpenSSL Project for use in the O No block source available... - + Η πηγή του μπλοκ δεν ειναι διαθέσιμη... Processed %1 of %2 (estimated) blocks of transaction history. - + Μεταποιημένα %1 απο % 2 (κατ 'εκτίμηση) μπλοκ της ιστορίας της συναλλαγής. Processed %1 blocks of transaction history. - + Έγινε λήψη %1 μπλοκ ιστορικού συναλλαγών %n hour(s) - + %n ώρες %n ώρες %n day(s) - + %n ημέρες %n ημέρες %n week(s) - + %n εβδομαδες%n εβδομαδες %1 behind - + %1 πίσω Last received block was generated %1 ago. - + Το τελευταίο μπλοκ που ελήφθη δημιουργήθηκε %1 πριν. Transactions after this will not yet be visible. - + Οι συναλλαγές μετά από αυτό δεν θα είναι ακόμη ορατες. @@ -592,17 +598,19 @@ This product includes software developed by the OpenSSL Project for use in the O Warning - + Προειδοποίηση Information - + Πληροφορία This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? - + Η συναλλαγή ξεπερνάει το όριο. +Μπορεί να ολοκληρωθεί με μια αμοιβή των %1, η οποία αποδίδεται στους κόμβους που επεξεργάζονται τις συναλλαγές και βοηθούν στην υποστήριξη του δικτύου. +Θέλετε να συνεχίσετε; @@ -652,7 +660,7 @@ Address: %4 URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. - + Το URI δεν μπορεί να αναλυθεί! Αυτό μπορεί να προκληθεί από μια μη έγκυρη διεύθυνση Bitcoin ή ακατάλληλη παραμέτρο URI. @@ -667,7 +675,7 @@ Address: %4 A fatal error occurred. Bitcoin can no longer continue safely and will quit. - + Παρουσιάστηκε ανεπανόρθωτο σφάλμα. Το Bitcoin δεν μπορεί πλέον να συνεχίσει με ασφάλεια και θα τερματισθει. @@ -805,7 +813,7 @@ Address: %4 Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Η προαιρετική αμοιβή για κάθε kB επισπεύδει την επεξεργασία των συναλλαγών σας. Οι περισσότερες συναλλαγές είναι 1 kB. @@ -825,12 +833,12 @@ Address: %4 Reset all client options to default. - + Επαναφορα όλων των επιλογων του πελάτη σε default. &Reset Options - + Επαναφορα ρυθμίσεων @@ -850,7 +858,7 @@ Address: %4 Connect to the Bitcoin network through a SOCKS proxy (e.g. when connecting through Tor). - + Σύνδεση στο Bitcoin δίκτυο μέσω διαμεσολαβητή SOCKS4 (π.χ. για σύνδεση μέσω Tor) @@ -860,7 +868,7 @@ Address: %4 Proxy &IP: - + &IP διαμεσολαβητή: @@ -885,7 +893,7 @@ Address: %4 SOCKS version of the proxy (e.g. 5) - + SOCKS εκδοση του διαμεσολαβητη (e.g. 5) @@ -920,7 +928,7 @@ Address: %4 User Interface &language: - + Γλώσσα περιβάλλοντος εργασίας: @@ -970,12 +978,12 @@ Address: %4 Confirm options reset - + Επιβεβαιώση των επιλογων επαναφοράς Some settings may require a client restart to take effect. - + Για ορισμένες ρυθμίσεις πρεπει η επανεκκίνηση να τεθεί σε ισχύ. @@ -1011,7 +1019,7 @@ Address: %4 The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. - + Οι πληροφορίες που εμφανίζονται μπορεί να είναι ξεπερασμένες. Το πορτοφόλι σας συγχρονίζεται αυτόματα με το δίκτυο Bitcoin μετά από μια σύνδεση, αλλά αυτή η διαδικασία δεν έχει ακόμη ολοκληρωθεί. @@ -1036,7 +1044,7 @@ Address: %4 Mined balance that has not yet matured - + Εξορυγμενο υπόλοιπο που δεν έχει ακόμα ωριμάσει @@ -1065,7 +1073,7 @@ Address: %4 Cannot start bitcoin: click-to-pay handler - + Δεν είναι δυνατή η εκκίνηση του Bitcoin: click-to-pay handler @@ -1108,7 +1116,7 @@ Address: %4 The entered amount is invalid, please check. - + Το αναγραφόμενο ποσό δεν είναι έγκυρο, παρακαλούμε να το ελέγξετε. @@ -1160,7 +1168,7 @@ Address: %4 Using OpenSSL version - + Χρησιμοποιηση της OpenSSL εκδοσης @@ -1215,7 +1223,7 @@ Address: %4 Show the Bitcoin-Qt help message to get a list with possible Bitcoin command-line options. - + Εμφανιση του Bitcoin-Qt μήνυματος βοήθειας για να πάρετε μια λίστα με τις πιθανές επιλογές Bitcoin γραμμής εντολών. @@ -1235,22 +1243,22 @@ Address: %4 Bitcoin - Debug window - + Bitcoin - Παράθυρο αποσφαλμάτωσης Bitcoin Core - + Bitcoin Core Debug log file - + Αρχείο καταγραφής εντοπισμού σφαλμάτων Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files. - + Ανοίξτε το αρχείο καταγραφής εντοπισμού σφαλμάτων από τον τρέχοντα κατάλογο δεδομένων. Αυτό μπορεί να πάρει μερικά δευτερόλεπτα για τα μεγάλα αρχεία καταγραφής. @@ -1260,17 +1268,17 @@ Address: %4 Welcome to the Bitcoin RPC console. - + Καλώς ήρθατε στην Bitcoin RPC κονσόλα. Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - + Χρησιμοποιήστε το πάνω και κάτω βέλος για να περιηγηθείτε στο ιστορικο, και <b>Ctrl-L</b> για εκκαθαριση οθονης. Type <b>help</b> for an overview of available commands. - + Γράψτε <b>βοήθεια</b> για μια επισκόπηση των διαθέσιμων εντολών @@ -1295,7 +1303,7 @@ Address: %4 Add &Recipient - + &Προσθήκη αποδέκτη @@ -1325,7 +1333,7 @@ Address: %4 S&end - + Αποστολη @@ -1350,7 +1358,7 @@ Address: %4 The recipient address is not valid, please recheck. - + Η διεύθυνση του αποδέκτη δεν είναι σωστή. Παρακαλώ ελέγξτε ξανά. @@ -1375,7 +1383,7 @@ Address: %4 Error: Transaction creation failed! - + Σφάλμα: Η δημιουργία της συναλλαγής απέτυχε @@ -1403,7 +1411,7 @@ Address: %4 The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - + Διεύθυνση αποστολής της πληρωμής (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) @@ -1452,7 +1460,7 @@ Address: %4 Signatures - Sign / Verify a Message - + Υπογραφές - Είσοδος / Επαλήθευση μήνυματος @@ -1504,7 +1512,7 @@ Address: %4 Copy the current signature to the system clipboard - + Αντέγραφη της επιλεγμενης διεύθυνσης στο πρόχειρο του συστηματος @@ -1514,12 +1522,12 @@ Address: %4 Sign &Message - + Υπογραφη μήνυματος Reset all sign message fields - + Επαναφορά όλων των πεδίων μήνυματος @@ -1535,7 +1543,7 @@ Address: %4 Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. - + Πληκτρολογήστε την υπογραφή διεύθυνσης, μήνυμα (βεβαιωθείτε ότι έχετε αντιγράψει τις αλλαγές γραμμής, κενά, tabs, κ.λπ. ακριβώς) και την υπογραφή παρακάτω, για να ελέγξει το μήνυμα. Να είστε προσεκτικοί για να μην διαβάσετε περισσότερα στην υπογραφή ό, τι είναι στην υπογραφή ίδιο το μήνυμα , για να μην εξαπατηθούν από έναν άνθρωπο -in - the-middle επίθεση. @@ -1545,17 +1553,17 @@ Address: %4 Verify the message to ensure it was signed with the specified Bitcoin address - + Υπογράψτε ένα μήνυμα για ν' αποδείξετε πως υπογραφθηκε απο μια συγκεκριμένη διεύθυνση Bitcoin Verify &Message - + Επιβεβαίωση μηνύματος Reset all verify message fields - + Επαναφορά όλων επαλήθευμενων πεδίων μήνυματος @@ -1566,7 +1574,7 @@ Address: %4 Click "Sign Message" to generate signature - + Κάντε κλικ στο "Υπογραφή Μηνύματος" για να λάβετε την υπογραφή @@ -1591,17 +1599,17 @@ Address: %4 The entered address does not refer to a key. - + Η διεύθυνση που έχει εισαχθεί δεν αναφέρεται σε ένα πλήκτρο. Wallet unlock was cancelled. - + το ξεκλείδωμα του πορτοφολιού απέτυχε Private key for the entered address is not available. - + Το προσωπικό κλειδί εισαγμενης διευθυνσης δεν είναι διαθέσιμο. @@ -1627,7 +1635,7 @@ Address: %4 The signature did not match the message digest. - + Η υπογραφή δεν ταιριάζει με το μήνυμα. @@ -1645,7 +1653,7 @@ Address: %4 The Bitcoin developers - + Οι Bitcoin προγραμματιστές @@ -1683,7 +1691,7 @@ Address: %4 , broadcast through %n node(s) - + , έχει μεταδοθεί μέσω %n κόμβων, έχει μεταδοθεί μέσω %n κόμβων @@ -1698,7 +1706,7 @@ Address: %4 Generated - + Δημιουργία @@ -1717,7 +1725,7 @@ Address: %4 own address - + δική σας διεύθυνση @@ -1731,17 +1739,17 @@ Address: %4 Credit - + Πίστωση matures in %n more block(s) - + ωρίμανση σε %n επιπλέον μπλοκωρίμανση σε %n επιπλέον μπλοκ not accepted - + μη αποδεκτό @@ -1749,17 +1757,17 @@ Address: %4 Debit - + Debit Transaction fee - + Τέλος συναλλαγής Net amount - + Καθαρό ποσό @@ -1779,7 +1787,7 @@ Address: %4 Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - + Πρέπει να περιμένετε 120 μπλοκ πριν μπορέσετε να χρησιμοποιήσετε τα νομίσματα που έχετε δημιουργήσει. Το μπλοκ που δημιουργήσατε μεταδόθηκε στο δίκτυο για να συμπεριληφθεί στην αλυσίδα των μπλοκ. Αν δεν μπει σε αυτή θα μετατραπεί σε "μη αποδεκτό" και δε θα μπορεί να καταναλωθεί. Αυτό συμβαίνει σπάνια όταν κάποιος άλλος κόμβος δημιουργήσει ένα μπλοκ λίγα δευτερόλεπτα πριν από εσάς. @@ -1794,7 +1802,7 @@ Address: %4 Inputs - + εισροές @@ -1804,12 +1812,12 @@ Address: %4 true - + αληθής false - + αναληθής @@ -1819,7 +1827,7 @@ Address: %4 Open for %n more block(s) - + Ανοιχτό για %n μπλοκΑνοιχτό για %n μπλοκ @@ -1865,7 +1873,7 @@ Address: %4 Open for %n more block(s) - + Ανοιχτό για %n μπλοκΑνοιχτό για %n μπλοκ @@ -1890,7 +1898,7 @@ Address: %4 Mined balance will be available when it matures in %n more block(s) - + Το υπόλοιπο από την εξόρυξη θα είναι διαθέσιμο μετά από %n μπλοκΤο υπόλοιπο από την εξόρυξη θα είναι διαθέσιμο μετά από %n μπλοκ @@ -2049,7 +2057,7 @@ Address: %4 Copy transaction ID - + Αντιγραφη του ID Συναλλαγής @@ -2140,7 +2148,7 @@ Address: %4 &Export - + &Εξαγωγή @@ -2150,32 +2158,32 @@ Address: %4 Backup Wallet - + Αντίγραφο ασφαλείας του πορτοφολιού Wallet Data (*.dat) - + Αρχεία δεδομένων πορτοφολιού (*.dat) Backup Failed - + Αποτυχία κατά τη δημιουργία αντιγράφου There was an error trying to save the wallet data to the new location. - + Παρουσιάστηκε σφάλμα κατά την αποθήκευση των δεδομένων πορτοφολιού στη νέα τοποθεσία. Backup Successful - + Η δημιουργια αντιγραφου ασφαλειας πετυχε The wallet data was successfully saved to the new location. - + Τα δεδομένα πορτοφόλιου αποθηκεύτηκαν με επιτυχία στη νέα θέση. @@ -2243,7 +2251,7 @@ Address: %4 Connect to a node to retrieve peer addresses, and disconnect - + Σύνδεση σε έναν κόμβο για την ανάκτηση διευθύνσεων από ομοτίμους, και αποσυνδέσh @@ -2263,7 +2271,7 @@ Address: %4 An error occurred while setting up the RPC port %u for listening on IPv4: %s - + Ένα σφάλμα συνέβη καθώς προετοιμαζόταν η πόρτα RPC %u για αναμονή IPv4: %s @@ -2288,7 +2296,7 @@ Address: %4 Accept connections from outside (default: 1 if no -proxy or -connect) - + Να δέχεσαι συνδέσεις από έξω(προεπιλογή:1) @@ -2303,87 +2311,98 @@ If the file does not exist, create it with owner-readable-only file permissions. It is also recommended to set alertnotify so you are notified of problems; for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com - + %s, you must set a rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s - + Ένα σφάλμα συνέβη καθώς προετοιμαζόταν η υποδοχη RPC %u για αναμονη του IPv6, επεσε πισω στο IPv4:%s Bind to given address and always listen on it. Use [host]:port notation for IPv6 - + Αποθηκευση σε συγκεκριμένη διεύθυνση. Χρησιμοποιήστε τα πλήκτρα [Host] : συμβολισμός θύρα για IPv6 Cannot obtain a lock on data directory %s. Bitcoin is probably already running. - + Αδυναμία κλειδώματος του φακέλου δεδομένων %s. Πιθανώς το Bitcoin να είναι ήδη ενεργό. Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - + Σφάλμα: Η συναλλαγή απορρίφθηκε. +Αυτό ίσως οφείλεται στο ότι τα νομίσματά σας έχουν ήδη ξοδευτεί, π.χ. με την αντιγραφή του wallet.dat σε άλλο σύστημα και την χρήση τους εκεί, χωρίς η συναλλαγή να έχει καταγραφεί στο παρόν σύστημα. Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! - + Σφάλμα: Αυτή η συναλλαγή απαιτεί αμοιβή συναλλαγής τουλάχιστον %s λόγω του μεγέθους, πολυπλοκότητας ή της χρήσης πρόσφατης παραλαβής κεφαλαίου Execute command when a relevant alert is received (%s in cmd is replaced by message) - + Εκτέλεση της εντολής όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) - + Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ) Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) - + Ορίστε το μέγιστο μέγεθος των high-priority/low-fee συναλλαγων σε bytes (προεπιλογή: 27000) This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - + Αυτό είναι ένα προ-τεστ κυκλοφορίας - χρησιμοποιήστε το με δική σας ευθύνη - δεν χρησιμοποιείτε για εξόρυξη ή για αλλες εφαρμογές Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - + Προειδοποίηση: Η παράμετρος -paytxfee είναι πολύ υψηλή. Πρόκειται για την αμοιβή που θα πληρώνετε για κάθε συναλλαγή που θα στέλνετε. Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. - + Προειδοποίηση: Εμφανίσεις συναλλαγων δεν μπορεί να είναι σωστες! Μπορεί να χρειαστεί να αναβαθμίσετε, ή άλλοι κόμβοι μπορεί να χρειαστεί να αναβαθμίστουν. Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly. - + Προειδοποίηση: Παρακαλώ βεβαιωθείτε πως η ημερομηνία κι ώρα του συστήματός σας είναι σωστές. Αν το ρολόι του υπολογιστή σας πάει λάθος, ενδέχεται να μη λειτουργεί σωστά το Bitcoin. Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. - + Προειδοποίηση : Σφάλμα wallet.dat κατα την ανάγνωση ! Όλα τα κλειδιά αναγνωρισθηκαν σωστά, αλλά τα δεδομένα των συναλλαγών ή καταχωρήσεις στο βιβλίο διευθύνσεων μπορεί να είναι ελλιπείς ή λανθασμένα. Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. - + Προειδοποίηση : το αρχειο wallet.dat ειναι διεφθαρμένο, τα δεδομένα σώζονται ! Original wallet.dat αποθηκεύονται ως πορτοφόλι { timestamp } bak στο % s ? . . Αν το υπόλοιπο του ή τις συναλλαγές σας, είναι λάθος θα πρέπει να επαναφέρετε από ένα αντίγραφο ασφαλείας Attempt to recover private keys from a corrupt wallet.dat - + Προσπάθεια για ανακτησει ιδιωτικων κλειδιων από ενα διεφθαρμένο αρχειο wallet.dat Block creation options: - + Αποκλεισμός επιλογων δημιουργίας: @@ -2393,47 +2412,47 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Corrupted block database detected - + Εντοπισθηκε διεφθαρμενη βαση δεδομενων των μπλοκ Discover own IP address (default: 1 when listening and no -externalip) - + Ανακαλύψτε την δικη σας IP διεύθυνση (προεπιλογή: 1 όταν ακούει και δεν - externalip) Do you want to rebuild the block database now? - + Θελετε να δημιουργηθει τωρα η βαση δεδομενων του μπλοκ? Error initializing block database - + Σφάλμα κατά την ενεργοποίηση της βάσης δεδομένων μπλοκ Error initializing wallet database environment %s! - + Σφάλμα κατά την ενεργοποίηση της βάσης δεδομένων πορτοφόλιου %s! Error loading block database - + Σφάλμα φορτωσης της βασης δεδομενων των μπλοκ Error opening block database - + Σφάλμα φορτωσης της βασης δεδομενων των μπλοκ Error: Disk space is low! - + Προειδοποίηση: Χαμηλός χώρος στο δίσκο Error: Wallet locked, unable to create transaction! - + Σφάλμα: το πορτοφόλι είναι κλειδωμένο, δεν μπορεί να δημιουργηθεί συναλλαγή @@ -2443,167 +2462,167 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Failed to listen on any port. Use -listen=0 if you want this. - + ταλαιπωρηθειτε για να ακούσετε σε οποιαδήποτε θύρα. Χρήση - ακούστε = 0 , αν θέλετε αυτό. Failed to read block info - + Αποτυχία αναγνωσης των block πληροφοριων Failed to read block - + Η αναγνωση του μπλοκ απετυχε Failed to sync block index - + Ο συγχρονισμος του μπλοκ ευρετηριου απετυχε Failed to write block index - + Η δημιουργια του μπλοκ ευρετηριου απετυχε Failed to write block info - + Η δημιουργια των μπλοκ πληροφοριων απετυχε Failed to write block - + Η δημιουργια του μπλοκ απετυχε Failed to write file info - + Αδυναμία εγγραφής πληροφοριων αρχειου Failed to write to coin database - + Αποτυχία εγγραφής στη βάση δεδομένων νομίσματος Failed to write transaction index - + Αποτυχία εγγραφής δείκτη συναλλαγών Failed to write undo data - + Αποτυχία εγγραφής αναίρεσης δεδομένων Find peers using DNS lookup (default: 1 unless -connect) - + Βρες ομότιμους υπολογιστές χρησιμοποιώντας αναζήτηση DNS(προεπιλογή:1) Generate coins (default: 0) - + Δημιουργία νομισμάτων (προκαθορισμος: 0) How many blocks to check at startup (default: 288, 0 = all) - + Πόσα μπλοκ να ελέγχθουν κατά την εκκίνηση (προεπιλογή:288,0=όλα) How thorough the block verification is (0-4, default: 3) - + Πόσο εξονυχιστική να είναι η επιβεβαίωση του μπλοκ(0-4, προεπιλογή:3) Not enough file descriptors available. - + Δεν ειναι αρκετες περιγραφες αρχείων διαθέσιμες. Rebuild block chain index from current blk000??.dat files - + Εισαγωγή μπλοκ από εξωτερικό αρχείο blk000?.dat Set the number of threads to service RPC calls (default: 4) - + Ορίσμος του αριθμόυ θεματων στην υπηρεσία κλήσεων RPC (προεπιλογή: 4) Verifying blocks... - + Επαλήθευση των μπλοκ... Verifying wallet... - + Επαλήθευση πορτοφολιου... Imports blocks from external blk000??.dat file - + Εισαγωγή μπλοκ από εξωτερικό αρχείο blk000?.dat Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Ορίσμος του αριθμό των νημάτων ελέγχου σεναρίου (μέχρι 16, 0 = auto, <0 = αφήνουν τους πολλους πυρήνες δωρεάν, default: 0) Information - + Πληροφορία Invalid -tor address: '%s' - + Δεν είναι έγκυρη η διεύθυνση διαμεσολαβητή: '%s' Invalid amount for -minrelaytxfee=<amount>: '%s' - + Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' Invalid amount for -mintxfee=<amount>: '%s' - + Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' Maintain a full transaction index (default: 0) - + Διατηρήση ένος πλήρες ευρετήριου συναλλαγών (προεπιλογή: 0) Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) - + Μέγιστος buffer λήψης ανά σύνδεση, <n>*1000 bytes (προεπιλογή: 5000) Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) - + Μέγιστος buffer αποστολής ανά σύνδεση, <n>*1000 bytes (προεπιλογή: 1000) Only accept block chain matching built-in checkpoints (default: 1) - + Μονο αποδοχη αλυσίδας μπλοκ που ταιριάζει με τα ενσωματωμένα σημεία ελέγχου (προεπιλογή: 1) Only connect to nodes in network <net> (IPv4, IPv6 or Tor) - + Συνδέση μόνο σε κόμβους του δικτύου <net> (IPv4, IPv6 ή Tor) Output extra debugging information. Implies all other -debug* options - + Έξοδος επιπλέον πληροφοριών εντοπισμού σφαλμάτων Output extra network debugging information - + Έξοδος επιπλέον πληροφοριών εντοπισμού σφαλμάτων @@ -2613,12 +2632,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. SSL options: (see the Bitcoin Wiki for SSL setup instructions) - + Ρυθμίσεις SSL: (ανατρέξτε στο Bitcoin Wiki για οδηγίες ρυθμίσεων SSL) Select the version of socks proxy to use (4-5, default: 5) - + Επιλέξτε την έκδοση του διαμεσολαβητη για να χρησιμοποιήσετε (4-5 , προεπιλογή: 5) @@ -2633,22 +2652,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Set maximum block size in bytes (default: 250000) - + Ορίσμος του μέγιστου μέγεθος block σε bytes (προεπιλογή: 250000) Set minimum block size in bytes (default: 0) - + Ορίστε το μέγιστο μέγεθος block σε bytes (προεπιλογή: 0) Shrink debug.log file on client startup (default: 1 when no -debug) - + Συρρίκνωση του αρχείο debug.log κατα την εκκίνηση του πελάτη (προεπιλογή: 1 όταν δεν-debug) Signing transaction failed - + Η υπογραφή συναλλαγής απέτυχε @@ -2663,32 +2682,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Transaction amount too small - + Το ποσό της συναλλαγής είναι πολύ μικρο Transaction amounts must be positive - + Τα ποσά των συναλλαγών πρέπει να είναι θετικα Transaction too large - + Η συναλλαγή ειναι πολύ μεγάλη Use UPnP to map the listening port (default: 0) - + Χρησιμοποίηση του UPnP για την χρήση της πόρτας αναμονής (προεπιλογή:0) Use UPnP to map the listening port (default: 1 when listening) - + Χρησιμοποίηση του UPnP για την χρήση της πόρτας αναμονής (προεπιλογή:1) Use proxy to reach tor hidden services (default: same as -proxy) - + Χρήση διακομιστή μεσολάβησης για την επίτευξη των Tor κρυμμένων υπηρεσιων (προεπιλογή: ίδιο με το-proxy) @@ -2698,22 +2717,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Warning - + Προειδοποίηση Warning: This version is obsolete, upgrade required! - + Προειδοποίηση: Αυτή η έκδοση είναι ξεπερασμένη, απαιτείται αναβάθμιση You need to rebuild the databases using -reindex to change -txindex - + Θα πρέπει να ξαναχτίστουν οι βάσεις δεδομένων που χρησιμοποιούντε-Αναδημιουργία αλλάγων-txindex wallet.dat corrupt, salvage failed - + Το αρχειο wallet.dat ειναι διεφθαρμένο, η διάσωση απέτυχε @@ -2778,7 +2797,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Unable to bind to %s on this computer (bind returned error %d, %s) - + Αδύνατη η σύνδεση με τη θύρα %s αυτού του υπολογιστή (bind returned error %d, %s) @@ -2788,7 +2807,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Allow DNS lookups for -addnode, -seednode and -connect - + Να επιτρέπονται οι έλεγχοι DNS για προσθήκη και σύνδεση κόμβων @@ -2823,27 +2842,27 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Unknown network specified in -onlynet: '%s' - + Άγνωστo δίκτυο ορίζεται σε onlynet: '%s' Unknown -socks proxy version requested: %i - + Άγνωστo δίκτυο ορίζεται: %i Cannot resolve -bind address: '%s' - + Δεν μπορώ να γράψω την προεπιλεγμένη διεύθυνση: '%s' Cannot resolve -externalip address: '%s' - + Δεν μπορώ να γράψω την προεπιλεγμένη διεύθυνση: '%s' Invalid amount for -paytxfee=<amount>: '%s' - + Μη έγκυρο ποσό για την παράμετρο -paytxfee=<amount>: '%s' @@ -2868,7 +2887,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Unable to bind to %s on this computer. Bitcoin is probably already running. - + Αδύνατη η σύνδεση με τη θύρα %s αυτού του υπολογιστή. Το Bitcoin είναι πιθανώς ήδη ενεργό. diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 26e3993dd..7c584e954 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -71,7 +71,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. - Estas son tus direcciones Bitcoin para recibir pagos. Puedes utilizar una diferente por cada persona emisora para saber quién te está pagando. + Estas son sus direcciones Bitcoin para recibir pagos. Puede utilizar una diferente por cada persona emisora para saber quién le está pagando. @@ -262,7 +262,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. - IMPORTANTE: Cualquier copia de seguridad que haya realizado previamente de su fichero de billetera debe reemplazarse con el fichero de billetera encriptado recientemente creado. Por razones de seguridad, las copias de seguridad previas del fichero de billetera que no estaban encriptadas pasarán a estar inservibles en cuanto comience a usar la nueva billetera encriptada. + IMPORTANTE: Cualquier copia de seguridad que haya realizado previamente de su archivo de monedero debe reemplazarse con el nuevo archivo de monedero cifrado. Por razones de seguridad, las copias de seguridad previas del archivo de monedero no cifradas serán inservibles en cuanto comience a usar el nuevo monedero cifrado. @@ -504,7 +504,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. Sign messages with your Bitcoin addresses to prove you own them - Firmar mensajes con sus direcciones Bitcoin para probar la propiedad + Firmar mensajes con sus direcciones Bitcoin para demostrar la propiedad @@ -550,12 +550,12 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. No block source available... - Ninguna origen de bloque disponible ... + Ninguna fuente de bloques disponible ... Processed %1 of %2 (estimated) blocks of transaction history. - Se han procesado %1 de %2 (estimación) bloques de historia de transacción. + Se han procesado %1 de %2 bloques (estimados) del historial de transacciones. @@ -580,7 +580,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. %1 behind - %1 detrás + %1 atrás @@ -590,7 +590,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. Transactions after this will not yet be visible. - Las transacciones que vengan después de esta todavía no serán visibles. + Las transacciones posteriores a esta aún no están visibles. @@ -620,7 +620,7 @@ Eric Young (eay@cryptsoft.com) y el software UPnP escrito por Thomas Bernard. Catching up... - Recuperando... + Actualizando... @@ -813,7 +813,7 @@ Dirección: %4 Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - Tarifa de transacción opcional por kB que ayuda a asegurar que tus transacciones sean procesadas rápidamente. La mayoría de transacciones son de 1kB. + Tarifa de transacción opcional por kB que ayuda a asegurar que sus transacciones sean procesadas rápidamente. La mayoría de transacciones son de 1kB. @@ -1054,7 +1054,7 @@ Dirección: %4 Your current balance - Saldo actual + Su saldo actual @@ -2399,7 +2399,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. - Aviso: ¿Recuperados datos de wallet.dat corrupto! El wallet.dat original se ha guardado como wallet.{timestamp}.bak en %s; si hubiera errores en su saldo o transacciones, deberá restaurar una copia de respaldo. + Aviso: ¡Recuperados datos de wallet.dat corrupto! El wallet.dat original se ha guardado como wallet.{timestamp}.bak en %s; si hubiera errores en su saldo o transacciones, deberá restaurar una copia de seguridad. @@ -2929,7 +2929,7 @@ Por ejemplo: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Rescanning... - Rescaneando... + Reexplorando... diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index 93ac949e7..d7d0b7c78 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -43,12 +43,12 @@ This product includes software developed by the OpenSSL Project for use in the O Double-click to edit address or label - アドレスかレーベルを編集するのためにダブルクリックして + アドレスまたはラベルを編集するにはダブルクリック Create a new address - 新しいのアドレスを作る + 新規アドレスの作成 @@ -113,7 +113,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Delete - &消す + 削除(&D) @@ -138,17 +138,17 @@ This product includes software developed by the OpenSSL Project for use in the O Export Address Book Data - アドレス帳データーを輸出する + アドレス帳データをエクスポートする Comma separated file (*.csv) - テキスト CSV (*.csv) + CSVファイル (*.csv) Error exporting - エラー輸出 + エクスポートエラー @@ -161,7 +161,7 @@ This product includes software developed by the OpenSSL Project for use in the O Label - レーベル + ラベル @@ -171,7 +171,7 @@ This product includes software developed by the OpenSSL Project for use in the O (no label) - (レーベル無し) + (ラベル無し) @@ -184,62 +184,62 @@ This product includes software developed by the OpenSSL Project for use in the O Enter passphrase - パスフレーズを入って + パスフレーズを入力 New passphrase - 新しいのパスフレーズ + 新しいパスフレーズ Repeat new passphrase - 新しいのパスフレーズを繰り返して + 新しいパスフレーズをもう一度 Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. - 財布の新しいのパスフレーズを入って。<br/><b>8個以上のワードか10個以上のランダムな文字</b>を使ってください。 + ウォレットの新しいパスフレーズを入力してください。<br/><b>8個以上の単語か10個以上のランダムな文字</b>を使ってください。 Encrypt wallet - 財布を暗号化する + ウォレットを暗号化する This operation needs your wallet passphrase to unlock the wallet. - この動作は財布のアンロックするように財布のパスフレーズが必要です。 + この操作はウォレットをアンロックするためにパスフレーズが必要です。 Unlock wallet - 財布をアンロックする + ウォレットをアンロックする This operation needs your wallet passphrase to decrypt the wallet. - この動作は財布の解読するように財布のパスフレーズが必要です。 + この操作はウォレットの暗号化解除のためにパスフレーズが必要です。 Decrypt wallet - 財布を解読する + ウォレットの暗号化を解除する Change passphrase - パスフレーズを変わります + パスフレーズの変更 Enter the old and new passphrase to the wallet. - 前と新しいの財布のパスフレーズを入って。 + 新旧両方のパスフレーズを入力してください。 Confirm wallet encryption - 財布の暗号化を確認する + ウォレットの暗号化を確認する @@ -266,7 +266,7 @@ This product includes software developed by the OpenSSL Project for use in the O Wallet encrypted - 財布は暗号化しました + ウォレットは暗号化されました @@ -279,35 +279,35 @@ This product includes software developed by the OpenSSL Project for use in the O Wallet encryption failed - 財布の暗号化するのは失敗しました + ウォレットの暗号化に失敗しました Wallet encryption failed due to an internal error. Your wallet was not encrypted. - 内部エラーですから財布の暗号化が失敗しました。財布は暗号化しませんでした。 + 内部エラーによりウォレットの暗号化が失敗しました。ウォレットは暗号化されませんでした。 The supplied passphrases do not match. - パスフレーズは同じではありません。 + パスフレーズが同じではありません。 Wallet unlock failed - 財布のアンロックは失敗しました + ウォレットのアンロックに失敗しました The passphrase entered for the wallet decryption was incorrect. - 財布の + ウォレットの暗号化解除のパスフレーズが正しくありません。 Wallet decryption failed - 財布の解読は失敗しました + ウォレットの暗号化解除に失敗しました @@ -325,37 +325,37 @@ This product includes software developed by the OpenSSL Project for use in the O Synchronizing with network... - ネットワークと同期化中。。。 + ネットワークに同期中…… &Overview - &概観 + 概要(&O) Show general overview of wallet - 財布の概観を見せる + ウォレットの概要を見る &Transactions - &取引 + 取引(&T) Browse transaction history - 昔の取引をブラウズする + 取引履歴を閲覧 Edit the list of stored addresses and labels - アドレスとレーベルのリストを編集する + 保存されたアドレスとラベルのリストを編集 Show the list of addresses for receiving payments - 支払いを受け取るのアドレスのリストを見せる + 支払い受け取り用アドレスのリストを見る @@ -365,12 +365,12 @@ This product includes software developed by the OpenSSL Project for use in the O Quit application - アプリを終了 + アプリケーションを終了 Show information about Bitcoin - Bitcoinの事の情報を見せる + Bitcoinに関する情報を見る @@ -385,7 +385,7 @@ This product includes software developed by the OpenSSL Project for use in the O &Options... - &オプションズ + オプション(&O) @@ -430,7 +430,7 @@ This product includes software developed by the OpenSSL Project for use in the O Change the passphrase used for wallet encryption - 財布の暗号化のためのパスフレーズを変わる + ウォレット暗号化用パスフレーズの変更 @@ -506,17 +506,17 @@ This product includes software developed by the OpenSSL Project for use in the O &File - &ファイル + ファイル(&F) &Settings - &設定 + 設定(&S) &Help - &ヘルプ + ヘルプ(&H) @@ -527,7 +527,7 @@ This product includes software developed by the OpenSSL Project for use in the O [testnet] - [テストネット] + [testnet] @@ -607,12 +607,12 @@ This product includes software developed by the OpenSSL Project for use in the O Up to date - 新しいのバージョンが無し + バージョンは最新です Catching up... - 追いつく中。。。 + @@ -622,12 +622,12 @@ This product includes software developed by the OpenSSL Project for use in the O Sent transaction - 送ったの取引 + 送金取引 Incoming transaction - 入ってくるの取引 + 着金取引 @@ -653,12 +653,12 @@ Address: %4 Wallet is <b>encrypted</b> and currently <b>unlocked</b> - 財布は<b>暗号化とアンロックです</b> + ウォレットは<b>暗号化され、アンロックされています</b> Wallet is <b>encrypted</b> and currently <b>locked</b> - 財布は<b>暗号化とロックです</b> + ウォレットは<b>暗号化され、ロックされています</b> @@ -679,12 +679,12 @@ Address: %4 Edit Address - アドレスを編集する + アドレスの編集 &Label - &レーベル + ラベル(&L) @@ -1646,7 +1646,7 @@ Address: %4 [testnet] - + [testnet] diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index f444d461f..35b951614 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -809,7 +809,7 @@ Inscriptio: %4 Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. - + Optionalis merces transactionum singulis kB quae adiuvat curare tuas transactiones processas esse celeriter. Plurimi transactiones 1kB sunt. @@ -2136,7 +2136,7 @@ Inscriptio: %4 Send Coins - + Mitte Nummos @@ -2144,7 +2144,7 @@ Inscriptio: %4 &Export - + &Exporta @@ -2517,7 +2517,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Generate coins (default: 0) - + Genera nummos (praedefinitum: 0) @@ -2532,7 +2532,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Not enough file descriptors available. - + Inopia descriptorum plicarum. @@ -2562,7 +2562,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + Constitue numerum filorum verificationis scriptorum (Maximum 16, 0 = auto, <0 = tot corda libera erunt, praedefinitum: 0) @@ -2577,12 +2577,12 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Invalid amount for -minrelaytxfee=<amount>: '%s' - + Quantitas non valida pro -minrelaytxfee=<amount>: '%s' Invalid amount for -mintxfee=<amount>: '%s' - + Quantitas non valida pro -mintxfee=<amount>: '%s' @@ -2662,7 +2662,7 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Signing transaction failed - + Signandum transactionis abortum est @@ -2677,17 +2677,17 @@ exempli gratia: alertnotify=echo %%s | mail -s "Bitcoin Notificatio" a Transaction amount too small - + Magnitudo transactionis nimis parva Transaction amounts must be positive - + Necesse est magnitudines transactionum positivas esse. Transaction too large - + Transactio nimis magna diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 8a5850d31..4048cc013 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -2578,12 +2578,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Invalid amount for -minrelaytxfee=<amount>: '%s' - + Ongeldig bedrag voor -minrelaytxfee=<bedrag>: '%s' Invalid amount for -mintxfee=<amount>: '%s' - + Ongeldig bedrag voor -mintxfee=<bedrag>: '%s' @@ -2663,7 +2663,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Signing transaction failed - + Ondertekenen van transactie mislukt @@ -2678,17 +2678,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Transaction amount too small - + Transactiebedrag te klein Transaction amounts must be positive - + Transactiebedragen moeten positief zijn Transaction too large - + Transactie te groot diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index fbf536e73..3399f7ad9 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -35,7 +35,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS The Bitcoin developers - + Desenvolvedores do Bitcoin @@ -103,7 +103,7 @@ Este produto inclui software desenvolvido pelo Projeto OpenSSL para uso no OpenS &Export - + &Exportar @@ -1649,7 +1649,7 @@ Endereço: %4 The Bitcoin developers - + Desenvolvedores do Bitcoin @@ -2144,7 +2144,7 @@ Endereço: %4 &Export - + &Exportar diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 0aed1f429..e2b6af501 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -2578,12 +2578,12 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Invalid amount for -minrelaytxfee=<amount>: '%s' - + Quantia inválida para -minrelaytxfee=<amount>: '%s' Invalid amount for -mintxfee=<amount>: '%s' - + Quantia inválida para -mintxfee=<amount>: '%s' @@ -2663,7 +2663,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Signing transaction failed - + Falhou assinatura da transação @@ -2678,17 +2678,17 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta Bitcoin" admin@foo Transaction amount too small - + Quantia da transação é muito baixa Transaction amounts must be positive - + Quantia da transação deverá ser positiva Transaction too large - + Transação grande demais diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index cebdff0e0..72d8a8d57 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -435,12 +435,12 @@ This product includes software developed by the OpenSSL Project for use in the O &Debug window - + &Okno pre ladenie Open debugging and diagnostic console - + Otvor konzolu pre ladenie a diagnostiku @@ -532,7 +532,7 @@ This product includes software developed by the OpenSSL Project for use in the O Bitcoin client - + Bitcoin klient @@ -617,7 +617,7 @@ This product includes software developed by the OpenSSL Project for use in the O Confirm transaction fee - + Potvrď poplatok za transakciu. @@ -1102,7 +1102,7 @@ Adresa: %4 Error encoding URI into QR Code. - + Chyba v zakódovaní URI do QR kódu @@ -1112,17 +1112,17 @@ Adresa: %4 Resulting URI too long, try to reduce the text for label / message. - + Výsledné URI príliš dlhé, skráť text pre názov / správu. Save QR Code - + Ukladanie QR kódu PNG Images (*.png) - + PNG obrázky (*.png) @@ -1130,7 +1130,7 @@ Adresa: %4 Client name - + Meno klienta @@ -1144,12 +1144,12 @@ Adresa: %4 N/A - + nie je k dispozícii Client version - + Verzia klienta @@ -1169,27 +1169,27 @@ Adresa: %4 Network - + Sieť Number of connections - + Počet pripojení On testnet - + Na testovacej sieti Block chain - + Reťazec blokov Current number of blocks - + Aktuálny počet blokov @@ -2227,7 +2227,7 @@ Adresa: %4 Set database cache size in megabytes (default: 25) - + Veľkosť vyrovnávajúcej pamäte pre databázu v megabytoch (predvolené:25) @@ -2252,12 +2252,12 @@ Adresa: %4 Threshold for disconnecting misbehaving peers (default: 100) - + Hranica pre odpojenie zle sa správajúcich peerov (predvolené: 100) Number of seconds to keep misbehaving peers from reconnecting (default: 86400) - + Počet sekúnd kedy sa zabráni zle sa správajúcim peerom znovupripojenie (predvolené: 86400) @@ -2732,12 +2732,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Execute command when the best block changes (%s in cmd is replaced by block hash) - + Vykonaj príkaz, ak zmeny v najlepšom bloku (%s v príkaze nahradí blok hash) Upgrade wallet to latest format - + Aktualizuj peňaženku na najnovší formát. @@ -2852,7 +2852,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Insufficient funds - + Nedostatok prostriedkov @@ -2862,7 +2862,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Add a node to connect to and attempt to keep the connection open - Pridať nódu a pripojiť sa and attempt to keep the connection open + Pridať nód na pripojenie a pokus o udržanie pripojenia otvoreného @@ -2882,12 +2882,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. Cannot downgrade wallet - + Nie je možné prejsť na nižšiu verziu peňaženky Cannot write default address - + Nie je možné zapísať predvolenú adresu. @@ -2902,7 +2902,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. To use the %s option - + Použiť %s možnosť. @@ -2914,7 +2914,9 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions. - + Musíš nastaviť rpcpassword=<heslo> v konfiguračnom súbore: +%s +Ak súbor neexistuje, vytvor ho s oprávnením pre čítanie len vlastníkom (owner-readable-only) \ No newline at end of file diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 94e642758..1b4e6c76e 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -2573,7 +2573,7 @@ alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0) - + 設定指令碼驗證的執行緒數目 (最多為 16, 若為 0 表示程式自動決定, 小於 0 表示保留不用的處理器核心數目, 預設為 0) From 173601705ccf189fd83e3854f71f6a872c6faeda Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Sun, 19 May 2013 12:45:52 -0400 Subject: [PATCH 41/69] fix memory leak in CKey::SetCompactSignature() --- src/key.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/key.cpp b/src/key.cpp index 20114e6bb..74b2797d8 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -367,6 +367,7 @@ bool CKey::SetCompactSignature(uint256 hash, const std::vector& v ECDSA_SIG_free(sig); return true; } + ECDSA_SIG_free(sig); return false; } From a9280652ce61ddbbecfe16e18e1e464bb1f5d34d Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Sun, 19 May 2013 15:46:11 -0400 Subject: [PATCH 42/69] Fix memory leak on exception in Key::SignCompact --- src/key.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/key.cpp b/src/key.cpp index 74b2797d8..75114c6af 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -328,7 +328,10 @@ bool CKey::SignCompact(uint256 hash, std::vector& vchSig) } if (nRecId == -1) + { + ECDSA_SIG_free(sig); throw key_error("CKey::SignCompact() : unable to construct recoverable key"); + } vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); From 2341e9b533fedf9bade5b55d676b2c0cf5ed8604 Mon Sep 17 00:00:00 2001 From: super3 Date: Mon, 20 May 2013 00:30:00 -0400 Subject: [PATCH 43/69] Docs Markdown Cleanup --- doc/README | 33 ---- doc/README.md | 46 +++++ doc/{build-msw.txt => build-msw.md} | 66 +++---- doc/{build-unix.txt => build-unix.md} | 118 +++++++------ doc/coding.md | 94 ++++++++++ doc/coding.txt | 96 ---------- doc/{multiwallet-qt.txt => multiwallet-qt.md} | 11 +- doc/{release-notes.txt => release-notes.md} | 46 ++--- doc/release-process.md | 164 ++++++++++++++++++ doc/release-process.txt | 144 --------------- doc/{unit-tests.txt => unit-tests.md} | 24 +-- 11 files changed, 443 insertions(+), 399 deletions(-) delete mode 100644 doc/README create mode 100644 doc/README.md rename doc/{build-msw.txt => build-msw.md} (55%) rename doc/{build-unix.txt => build-unix.md} (64%) create mode 100644 doc/coding.md delete mode 100644 doc/coding.txt rename doc/{multiwallet-qt.txt => multiwallet-qt.md} (89%) rename doc/{release-notes.txt => release-notes.md} (55%) create mode 100644 doc/release-process.md delete mode 100644 doc/release-process.txt rename doc/{unit-tests.txt => unit-tests.md} (55%) diff --git a/doc/README b/doc/README deleted file mode 100644 index ecd9c6036..000000000 --- a/doc/README +++ /dev/null @@ -1,33 +0,0 @@ -Bitcoin 0.8.2 BETA - -Copyright (c) 2009-2013 Bitcoin Developers -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in -the OpenSSL Toolkit (http://www.openssl.org/). This product includes -cryptographic software written by Eric Young (eay@cryptsoft.com). - - -Intro ------ -Bitcoin is a free open source peer-to-peer electronic cash system that is -completely decentralized, without the need for a central server or trusted -parties. Users hold the crypto keys to their own money and transact directly -with each other, with the help of a P2P network to check for double-spending. - - -Setup ------ -You need the Qt4 run-time libraries to run Bitcoin-Qt. On Debian or Ubuntu: - sudo apt-get install libqtgui4 - -Unpack the files into a directory and run: - bin/32/bitcoin-qt (GUI, 32-bit) - bin/32/bitcoind (headless, 32-bit) - bin/64/bitcoin-qt (GUI, 64-bit) - bin/64/bitcoind (headless, 64-bit) - - -See the documentation at the bitcoin wiki: - https://en.bitcoin.it/wiki/Main_Page -for help and more information. diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 000000000..cdd31057a --- /dev/null +++ b/doc/README.md @@ -0,0 +1,46 @@ +Bitcoin 0.8.2 BETA +==================== + +Copyright (c) 2009-2013 Bitcoin Developers + +Distributed under the MIT/X11 software license, see the accompanying +file COPYING or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes +cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. + + +Intro +--------------------- +Bitcoin is a free open source peer-to-peer electronic cash system that is +completely decentralized, without the need for a central server or trusted +parties. Users hold the crypto keys to their own money and transact directly +with each other, with the help of a P2P network to check for double-spending. + + +Setup +--------------------- +You need the Qt4 run-time libraries to run Bitcoin-Qt. On Debian or Ubuntu: + `sudo apt-get install libqtgui4` + +Unpack the files into a directory and run: + +- bin/32/bitcoin-qt (GUI, 32-bit) +- bin/32/bitcoind (headless, 32-bit) +- bin/64/bitcoin-qt (GUI, 64-bit) +- bin/64/bitcoind (headless, 64-bit) + +See the documentation at the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page) +for help and more information. + + +Other Pages +--------------------- +- [Unix Build Notes](build-unix.md) +- [OSX Build Notes](build-osx.md) +- [Windows Build Notes](build-msw.md) +- [Coding Guidelines](coding.md) +- [Release Process](release-process.md) +- [Release Notes](release-notes.md) +- [Multiwallet Qt Development](multiwallet-qt.md) +- [Unit Tests](unit-tests.md) +- [Translation Process](translation_process.md) \ No newline at end of file diff --git a/doc/build-msw.txt b/doc/build-msw.md similarity index 55% rename from doc/build-msw.txt rename to doc/build-msw.md index 3e64813b3..b7abe2887 100644 --- a/doc/build-msw.txt +++ b/doc/build-msw.md @@ -1,10 +1,9 @@ -Copyright (c) 2009-2012 Bitcoin Developers +Copyright (c) 2009-2013 Bitcoin Developers + Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in -the OpenSSL Toolkit (http://www.openssl.org/). This product includes -cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP -software written by Thomas Bernard. +This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes +cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. See readme-qt.rst for instructions on building Bitcoin-Qt, the @@ -30,55 +29,62 @@ Boost \boost-1.50.0-mgw http://www.boost.org/users/download/ miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/ Their licenses: -OpenSSL Old BSD license with the problematic advertising requirement -Berkeley DB New BSD license with additional requirement that linked software must be free open source -Boost MIT-like license -miniupnpc New (3-clause) BSD license + + OpenSSL Old BSD license with the problematic advertising requirement + Berkeley DB New BSD license with additional requirement that linked software must be free open source + Boost MIT-like license + miniupnpc New (3-clause) BSD license Versions used in this release: -OpenSSL 1.0.1c -Berkeley DB 4.8.30.NC -Boost 1.50.0 -miniupnpc 1.6 + + OpenSSL 1.0.1c + Berkeley DB 4.8.30.NC + Boost 1.50.0 + miniupnpc 1.6 OpenSSL ------- MSYS shell: + un-tar sources with MSYS 'tar xfz' to avoid issue with symlinks (OpenSSL ticket 2377) change 'MAKE' env. variable from 'C:\MinGW32\bin\mingw32-make.exe' to '/c/MinGW32/bin/mingw32-make.exe' -cd /c/openssl-1.0.1c-mgw -./config -make + cd /c/openssl-1.0.1c-mgw + ./config + make Berkeley DB ----------- MSYS shell: -cd /c/db-4.8.30.NC-mgw/build_unix -sh ../dist/configure --enable-mingw --enable-cxx -make + + cd /c/db-4.8.30.NC-mgw/build_unix + sh ../dist/configure --enable-mingw --enable-cxx + make Boost ----- DOS prompt: -downloaded boost jam 3.1.18 -cd \boost-1.50.0-mgw -bjam toolset=gcc --build-type=complete stage + + downloaded boost jam 3.1.18 + cd \boost-1.50.0-mgw + bjam toolset=gcc --build-type=complete stage MiniUPnPc --------- -UPnP support is optional, make with USE_UPNP= to disable it. +UPnP support is optional, make with `USE_UPNP=` to disable it. MSYS shell: -cd /c/miniupnpc-1.6-mgw -make -f Makefile.mingw -mkdir miniupnpc -cp *.h miniupnpc/ + + cd /c/miniupnpc-1.6-mgw + make -f Makefile.mingw + mkdir miniupnpc + cp *.h miniupnpc/ Bitcoin ------- DOS prompt: -cd \bitcoin\src -mingw32-make -f makefile.mingw -strip bitcoind.exe + + cd \bitcoin\src + mingw32-make -f makefile.mingw + strip bitcoind.exe diff --git a/doc/build-unix.txt b/doc/build-unix.md similarity index 64% rename from doc/build-unix.txt rename to doc/build-unix.md index a1e24ff5d..6181bb255 100644 --- a/doc/build-unix.txt +++ b/doc/build-unix.md @@ -1,26 +1,23 @@ -Copyright (c) 2009-2012 Bitcoin Developers +Copyright (c) 2009-2013 Bitcoin Developers + Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in -the OpenSSL Toolkit (http://www.openssl.org/). This product includes -cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP -software written by Thomas Bernard. - +This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes +cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. UNIX BUILD NOTES -================ +==================== To Build --------- +--------------------- -cd src/ -make -f makefile.unix # Headless bitcoin + cd src/ + make -f makefile.unix # Headless bitcoin -See readme-qt.rst for instructions on building Bitcoin-Qt, -the graphical user interface. +See readme-qt.rst for instructions on building Bitcoin-Qt, the graphical user interface. Dependencies ------------- +--------------------- Library Purpose Description ------- ------- ----------- @@ -29,15 +26,17 @@ Dependencies libboost Boost C++ Library miniupnpc UPnP Support Optional firewall-jumping support -miniupnpc may be used for UPnP port mapping. It can be downloaded from -http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and +[miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here]( +http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and turned off by default. Set USE_UPNP to a different value to control this: - USE_UPNP=- No UPnP support - miniupnp not required - USE_UPNP=0 (the default) UPnP support turned off by default at runtime - USE_UPNP=1 UPnP support turned on by default at runtime + + USE_UPNP= No UPnP support miniupnp not required + USE_UPNP=0 (the default) UPnP support turned off by default at runtime + USE_UPNP=1 UPnP support turned on by default at runtime IPv6 support may be disabled by setting: - USE_IPV6=0 Disable IPv6 support + + USE_IPV6=0 Disable IPv6 support Licenses of statically linked libraries: Berkeley DB New BSD license with additional requirement that linked @@ -45,51 +44,54 @@ Licenses of statically linked libraries: Boost MIT-like license miniupnpc New (3-clause) BSD license -Versions used in this release: - GCC 4.3.3 - OpenSSL 1.0.1c - Berkeley DB 4.8.30.NC - Boost 1.37 - miniupnpc 1.6 +- Versions used in this release: +- GCC 4.3.3 +- OpenSSL 1.0.1c +- Berkeley DB 4.8.30.NC +- Boost 1.37 +- miniupnpc 1.6 Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- Build requirements: - sudo apt-get install build-essential - sudo apt-get install libssl-dev + + sudo apt-get install build-essential + sudo apt-get install libssl-dev for Ubuntu 12.04: - sudo apt-get install libboost-all-dev - db4.8 packages are available at: - https://launchpad.net/~bitcoin/+archive/bitcoin + sudo apt-get install libboost-all-dev + + db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). Ubuntu precise has packages for libdb5.1-dev and libdb5.1++-dev, but using these will break binary wallet compatibility, and is not recommended. for other Ubuntu & Debian: - sudo apt-get install libdb4.8-dev - sudo apt-get install libdb4.8++-dev - sudo apt-get install libboost1.37-dev + + sudo apt-get install libdb4.8-dev + sudo apt-get install libdb4.8++-dev + sudo apt-get install libboost1.37-dev (If using Boost 1.37, append -mt to the boost libraries in the makefile) Optional: - sudo apt-get install libminiupnpc-dev (see USE_UPNP compile flag) + + sudo apt-get install libminiupnpc-dev (see USE_UPNP compile flag) Dependency Build Instructions: Gentoo ------------------------------------- -Note: If you just want to install bitcoind on Gentoo, you can add the Bitcoin - overlay and use your package manager: - layman -a bitcoin && emerge bitcoind +Note: If you just want to install bitcoind on Gentoo, you can add the Bitcoin overlay and use your package manager: -emerge -av1 --noreplace boost glib openssl sys-libs/db:4.8 + layman -a bitcoin && emerge bitcoind + emerge -av1 --noreplace boost glib openssl sys-libs/db:4.8 Take the following steps to build (no UPnP support): - cd ${BITCOIN_DIR}/src - make -f makefile.unix USE_UPNP= USE_IPV6=1 BDB_INCLUDE_PATH='/usr/include/db4.8' - strip bitcoind + + cd ${BITCOIN_DIR}/src + make -f makefile.unix USE_UPNP= USE_IPV6=1 BDB_INCLUDE_PATH='/usr/include/db4.8' + strip bitcoind Notes @@ -100,26 +102,28 @@ symbols, which reduces the executable size by about 90%. miniupnpc --------- -tar -xzvf miniupnpc-1.6.tar.gz -cd miniupnpc-1.6 -make -sudo su -make install + tar -xzvf miniupnpc-1.6.tar.gz + cd miniupnpc-1.6 + make + sudo su + make install Berkeley DB ----------- You need Berkeley DB 4.8. If you have to build Berkeley DB yourself: -../dist/configure --enable-cxx -make + + ../dist/configure --enable-cxx + make Boost ----- If you need to build Boost yourself: -sudo su -./bootstrap.sh -./bjam install + + sudo su + ./bootstrap.sh + ./bjam install Security @@ -138,10 +142,12 @@ exploit even if a vulnerability is found, you can take the following measures: such as: "relocation R_X86_64_32 against `......' can not be used when making a shared object;" To build with PIE, use: - make -f makefile.unix ... -e PIE=1 + + make -f makefile.unix ... -e PIE=1 To test that you have built PIE executable, install scanelf, part of paxutils, and use: - scanelf -e ./bitcoin + + scanelf -e ./bitcoin The output should contain: TYPE @@ -155,10 +161,10 @@ exploit even if a vulnerability is found, you can take the following measures: executable without the non-executable stack protection. To verify that the stack is non-executable after compiling use: - scanelf -e ./bitcoin + `scanelf -e ./bitcoin` the output should contain: - STK/REL/PTL - RW- R-- RW- + STK/REL/PTL + RW- R-- RW- The STK RW- means that the stack is readable and writeable but not executable. diff --git a/doc/coding.md b/doc/coding.md new file mode 100644 index 000000000..3581d7deb --- /dev/null +++ b/doc/coding.md @@ -0,0 +1,94 @@ +Coding +==================== + +Please be consistent with the existing coding style. + +Block style: + + bool Function(char* psz, int n) + { + // Comment summarising what this section of code does + for (int i = 0; i < n; i++) + { + // When something fails, return early + if (!Something()) + return false; + ... + } + + // Success return is usually at the end + return true; + } + +- ANSI/Allman block style +- 4 space indenting, no tabs +- No extra spaces inside parenthesis; please don't do ( this ) +- No space after function names, one space after if, for and while + +Variable names begin with the type in lowercase, like nSomeVariable. +Please don't put the first word of the variable name in lowercase like +someVariable. + +Common types: + + n integer number: short, unsigned short, int, unsigned int, int64, uint64, sometimes char if used as a number + d double, float + f flag + hash uint256 + p pointer or array, one p for each level of indirection + psz pointer to null terminated string + str string object + v vector or similar list objects + map map or multimap + set set or multiset + bn CBigNum + +------------------------- +Locking/mutex usage notes + +The code is multi-threaded, and uses mutexes and the +LOCK/TRY_LOCK macros to protect data structures. + +Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main +and then cs_wallet, while thread 2 locks them in the opposite order: +result, deadlock as each waits for the other to release its lock) are +a problem. Compile with -DDEBUG_LOCKORDER to get lock order +inconsistencies reported in the debug.log file. + +Re-architecting the core code so there are better-defined interfaces +between the various components is a goal, with any necessary locking +done by the components (e.g. see the self-contained CKeyStore class +and its cs_KeyStore lock for example). + +------- +Threads + +- StartNode : Starts other threads. + +- ThreadGetMyExternalIP : Determines outside-the-firewall IP address, sends addr message to connected peers when it determines it. + +- ThreadSocketHandler : Sends/Receives data from peers on port 8333. + +- ThreadMessageHandler : Higher-level message handling (sending and receiving). + +- ThreadOpenConnections : Initiates new connections to peers. + +- ThreadTopUpKeyPool : replenishes the keystore's keypool. + +- ThreadCleanWalletPassphrase : re-locks an encrypted wallet after user has unlocked it for a period of time. + +- SendingDialogStartTransfer : used by pay-via-ip-address code (obsolete) + +- ThreadDelayedRepaint : repaint the gui + +- ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used in 500ms. + +- ThreadRPCServer : Remote procedure call handler, listens on port 8332 for connections and services them. + +- ThreadBitcoinMiner : Generates bitcoins + +- ThreadMapPort : Universal plug-and-play startup/shutdown + +- Shutdown : Does an orderly shutdown of everything + +- ExitTimeout : Windows-only, sleeps 5 seconds then exits application diff --git a/doc/coding.txt b/doc/coding.txt deleted file mode 100644 index 427e388cf..000000000 --- a/doc/coding.txt +++ /dev/null @@ -1,96 +0,0 @@ -Please be consistent with the existing coding style. - -Block style: - -bool Function(char* psz, int n) -{ - // Comment summarising what this section of code does - for (int i = 0; i < n; i++) - { - // When something fails, return early - if (!Something()) - return false; - ... - } - - // Success return is usually at the end - return true; -} - -- ANSI/Allman block style -- 4 space indenting, no tabs -- No extra spaces inside parenthesis; please don't do ( this ) -- No space after function names, one space after if, for and while - -Variable names begin with the type in lowercase, like nSomeVariable. -Please don't put the first word of the variable name in lowercase like -someVariable. - -Common types: -n integer number: short, unsigned short, int, unsigned int, - int64, uint64, sometimes char if used as a number -d double, float -f flag -hash uint256 -p pointer or array, one p for each level of indirection -psz pointer to null terminated string -str string object -v vector or similar list objects -map map or multimap -set set or multiset -bn CBigNum - -------------------------- -Locking/mutex usage notes - -The code is multi-threaded, and uses mutexes and the -LOCK/TRY_LOCK macros to protect data structures. - -Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main -and then cs_wallet, while thread 2 locks them in the opposite order: -result, deadlock as each waits for the other to release its lock) are -a problem. Compile with -DDEBUG_LOCKORDER to get lock order -inconsistencies reported in the debug.log file. - -Re-architecting the core code so there are better-defined interfaces -between the various components is a goal, with any necessary locking -done by the components (e.g. see the self-contained CKeyStore class -and its cs_KeyStore lock for example). - -------- -Threads - -StartNode : Starts other threads. - -ThreadGetMyExternalIP : Determines outside-the-firewall IP address, -sends addr message to connected peers when it determines it. - -ThreadSocketHandler : Sends/Receives data from peers on port 8333. - -ThreadMessageHandler : Higher-level message handling (sending and -receiving). - -ThreadOpenConnections : Initiates new connections to peers. - -ThreadTopUpKeyPool : replenishes the keystore's keypool. - -ThreadCleanWalletPassphrase : re-locks an encrypted wallet after user -has unlocked it for a period of time. - -SendingDialogStartTransfer : used by pay-via-ip-address code (obsolete) - -ThreadDelayedRepaint : repaint the gui - -ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used -in 500ms. - -ThreadRPCServer : Remote procedure call handler, listens on port 8332 -for connections and services them. - -ThreadBitcoinMiner : Generates bitcoins - -ThreadMapPort : Universal plug-and-play startup/shutdown - -Shutdown : Does an orderly shutdown of everything - -ExitTimeout : Windows-only, sleeps 5 seconds then exits application diff --git a/doc/multiwallet-qt.txt b/doc/multiwallet-qt.md similarity index 89% rename from doc/multiwallet-qt.txt rename to doc/multiwallet-qt.md index 8394080db..8d695552b 100644 --- a/doc/multiwallet-qt.txt +++ b/doc/multiwallet-qt.md @@ -39,15 +39,14 @@ Changes to bitcoin.cpp bitcoin.cpp is the entry point into bitcoin-qt, and as such, will require some minor modifications to provide hooks for multiple wallet support. Most importantly will be the way it instantiates WalletModels and passes them to the singleton BitcoinGUI instance called window. Formerly, BitcoinGUI kept a pointer to a single instance of a WalletModel. -The initial change required is very simple: rather than calling window.setWalletModel(&walletModel); we perform the +The initial change required is very simple: rather than calling `window.setWalletModel(&walletModel);` we perform the following two steps: -window.addWallet("~Default", &walletModel); -window.setCurrentWallet("~Default"); + window.addWallet("~Default", &walletModel); + window.setCurrentWallet("~Default"); -The string parameter is just an arbitrary name given to the default wallet. It's been prepended with a tilde to avoid name -collisions in the future with additional wallets. +The string parameter is just an arbitrary name given to the default wallet. It's been prepended with a tilde to avoid name collisions in the future with additional wallets. -The shutdown call window.setWalletModel(0) has also been removed. In its place is now: +The shutdown call `window.setWalletModel(0)` has also been removed. In its place is now: window.removeAllWallets(); diff --git a/doc/release-notes.txt b/doc/release-notes.md similarity index 55% rename from doc/release-notes.txt rename to doc/release-notes.md index 36b2f7530..0e0b04bca 100644 --- a/doc/release-notes.txt +++ b/doc/release-notes.md @@ -26,41 +26,41 @@ the rest of the network your transactions may never confirm. Bitcoin-Qt changes ------------------ -* New icon and splash screen -* Improve reporting of synchronization process -* Remove hardcoded fee recommendations -* Improve metadata of executable on MacOSX and Windows -* Move export button to individual tabs instead of toolbar -* Add "send coins" command to context menu in address book -* Add "copy txid" command to copy transaction IDs from transaction overview -* Save & restore window size and position when showing & hiding window -* New translations: Arabic (ar), Bosnian (bs), Catalan (ca), Welsh (cy), - Esperanto (eo), Interlingua (la), Latvian (lv) and many improvements - to current translations +- New icon and splash screen +- Improve reporting of synchronization process +- Remove hardcoded fee recommendations +- Improve metadata of executable on MacOSX and Windows +- Move export button to individual tabs instead of toolbar +- Add "send coins" command to context menu in address book +- Add "copy txid" command to copy transaction IDs from transaction overview +- Save & restore window size and position when showing & hiding window +- New translations: Arabic (ar), Bosnian (bs), Catalan (ca), Welsh (cy), Esperanto (eo), Interlingua (la), Latvian (lv) and many improvements to current translations MacOSX: -* OSX support for click-to-pay (bitcoin:) links -* Fix GUI disappearing problem on MacOSX (issue #1522) + +- OSX support for click-to-pay (bitcoin:) links +- Fix GUI disappearing problem on MacOSX (issue #1522) Linux/Unix: -* Copy addresses to middle-mouse-button clipboard + +- Copy addresses to middle-mouse-button clipboard Command-line options -------------------- -* -walletnotify will call a command on receiving transactions that affect the wallet. -* -alertnotify will call a command on receiving an alert from the network. -* -par now takes a negative number, to leave a certain amount of cores free. +* `-walletnotify` will call a command on receiving transactions that affect the wallet. +* `-alertnotify` will call a command on receiving an alert from the network. +* `-par` now takes a negative number, to leave a certain amount of cores free. JSON-RPC API changes -------------------- -* listunspent now lists account and address infromation. -* getinfo now also returns the time adjustment estimated from your peers. -* getpeerinfo now returns bytessent, bytesrecv and syncnode. -* gettxoutsetinfo returns statistics about the unspent transaction output database. -* gettxout returns information about a specific unspent transaction output. +* `listunspent` now lists account and address infromation. +* `getinfo` now also returns the time adjustment estimated from your peers. +* `getpeerinfo` now returns bytessent, bytesrecv and syncnode. +* `gettxoutsetinfo` returns statistics about the unspent transaction output database. +* `gettxout` returns information about a specific unspent transaction output. Networking changes @@ -76,5 +76,5 @@ Wallet compatibility/rescuing ----------------------------- * Cases where wallets cannot be opened in another version/installation should be reduced. -* -salvagewallet now works for encrypted wallets. +* `-salvagewallet` now works for encrypted wallets. diff --git a/doc/release-process.md b/doc/release-process.md new file mode 100644 index 000000000..17d6a089c --- /dev/null +++ b/doc/release-process.md @@ -0,0 +1,164 @@ +Release Process +==================== + +* update translations (ping wumpus, Diapolo or tcatm on IRC) +* see https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#syncing-with-transifex + +* * * + +###update (commit) version in sources + + + bitcoin-qt.pro + contrib/verifysfbinaries/verify.sh + doc/README* + share/setup.nsi + src/clientversion.h (change CLIENT_VERSION_IS_RELEASE to true) + +###tag version in git + + git tag -a v0.8.0 + +###write release notes. git shortlog helps a lot, for example: + + git shortlog --no-merges v0.7.2..v0.8.0 + +* * * + +##perform gitian builds + + From a directory containing the bitcoin source, gitian-builder and gitian.sigs + + export SIGNER=(your gitian key, ie bluematt, sipa, etc) + export VERSION=0.8.0 + cd ./gitian-builder + + Fetch and build inputs: (first time, or when dependency versions change) + + mkdir -p inputs; cd inputs/ + wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz + wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz' + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' + wget 'http://zlib.net/zlib-1.2.6.tar.gz' + wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz' + wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2' + wget 'http://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2' + wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz' + cd .. + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-win32.yml + mv build/out/boost-win32-1.50.0-gitian2.zip inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml + mv build/out/qt-win32-4.8.3-gitian-r1.zip inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/deps-win32.yml + mv build/out/bitcoin-deps-0.0.5.zip inputs/ + + Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32: + + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian.yml + ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml + pushd build/out + zip -r bitcoin-${VERSION}-linux-gitian.zip * + mv bitcoin-${VERSION}-linux-gitian.zip ../../ + popd + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + pushd build/out + zip -r bitcoin-${VERSION}-win32-gitian.zip * + mv bitcoin-${VERSION}-win32-gitian.zip ../../ + popd + + Build output expected: + + 1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip) + 2. windows 32-bit binary, installer + source (bitcoin-${VERSION}-win32-gitian.zip) + 3. Gitian signatures (in gitian.sigs/${VERSION}[-win32]/(your gitian key)/ + +repackage gitian builds for release as stand-alone zip/tar/installer exe + +**Linux .tar.gz:** + + unzip bitcoin-${VERSION}-linux-gitian.zip -d bitcoin-${VERSION}-linux + tar czvf bitcoin-${VERSION}-linux.tar.gz bitcoin-${VERSION}-linux + rm -rf bitcoin-${VERSION}-linux + +**Windows .zip and setup.exe:** + + unzip bitcoin-${VERSION}-win32-gitian.zip -d bitcoin-${VERSION}-win32 + mv bitcoin-${VERSION}-win32/bitcoin-*-setup.exe . + zip -r bitcoin-${VERSION}-win32.zip bitcoin-${VERSION}-win32 + rm -rf bitcoin-${VERSION}-win32 + +**Perform Mac build:** + + OSX binaries are created by Gavin Andresen on a 32-bit, OSX 10.6 machine. + + qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro + make + export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files + T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) + python2.7 share/qt/clean_mac_info_plist.py + python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist + + Build output expected: Bitcoin-Qt.dmg + +###Next steps: + +* Code-sign Windows -setup.exe (in a Windows virtual machine) and + OSX Bitcoin-Qt.app (Note: only Gavin has the code-signing keys currently) + +* upload builds to SourceForge + +* create SHA256SUMS for builds, and PGP-sign it + +* update bitcoin.org version + make sure all OS download links go to the right versions + +* update forum version + +* update wiki download links + +* update wiki changelog: [https://en.bitcoin.it/wiki/Changelog](https://en.bitcoin.it/wiki/Changelog) + +Commit your signature to gitian.sigs: + + pushd gitian.sigs + git add ${VERSION}/${SIGNER} + git add ${VERSION}-win32/${SIGNER} + git commit -a + git push # Assuming you can push to the gitian.sigs tree + popd + +------------------------------------------------------------------------- + +### After 3 or more people have gitian-built, repackage gitian-signed zips: + +From a directory containing bitcoin source, gitian.sigs and gitian zips + + export VERSION=0.5.1 + mkdir bitcoin-${VERSION}-linux-gitian + pushd bitcoin-${VERSION}-linux-gitian + unzip ../bitcoin-${VERSION}-linux-gitian.zip + mkdir gitian + cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ + for signer in $(ls ../gitian.sigs/${VERSION}/); do + cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig + done + zip -r bitcoin-${VERSION}-linux-gitian.zip * + cp bitcoin-${VERSION}-linux-gitian.zip ../ + popd + mkdir bitcoin-${VERSION}-win32-gitian + pushd bitcoin-${VERSION}-win32-gitian + unzip ../bitcoin-${VERSION}-win32-gitian.zip + mkdir gitian + cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ + for signer in $(ls ../gitian.sigs/${VERSION}-win32/); do + cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig + done + zip -r bitcoin-${VERSION}-win32-gitian.zip * + cp bitcoin-${VERSION}-win32-gitian.zip ../ + popd + +- Upload gitian zips to SourceForge +- Celebrate \ No newline at end of file diff --git a/doc/release-process.txt b/doc/release-process.txt deleted file mode 100644 index ce6614335..000000000 --- a/doc/release-process.txt +++ /dev/null @@ -1,144 +0,0 @@ -* update translations (ping wumpus, Diapolo or tcatm on IRC) - * see https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#syncing-with-transifex - -* update (commit) version in sources - bitcoin-qt.pro - contrib/verifysfbinaries/verify.sh - doc/README* - share/setup.nsi - src/clientversion.h (change CLIENT_VERSION_IS_RELEASE to true) - -* tag version in git - - git tag -a v0.8.0 - -* write release notes. git shortlog helps a lot, for example: - - git shortlog --no-merges v0.7.2..v0.8.0 - -* perform gitian builds - - * From a directory containing the bitcoin source, gitian-builder and gitian.sigs - export SIGNER=(your gitian key, ie bluematt, sipa, etc) - export VERSION=0.8.0 - cd ./gitian-builder - - * Fetch and build inputs: (first time, or when dependency versions change) - mkdir -p inputs; cd inputs/ - wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz - wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz' - wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' - wget 'http://zlib.net/zlib-1.2.6.tar.gz' - wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz' - wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2' - wget 'http://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2' - wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz' - cd .. - ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-win32.yml - mv build/out/boost-win32-1.50.0-gitian2.zip inputs/ - ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml - mv build/out/qt-win32-4.8.3-gitian-r1.zip inputs/ - ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/deps-win32.yml - mv build/out/bitcoin-deps-0.0.5.zip inputs/ - - * Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32: - ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian.yml - ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml - pushd build/out - zip -r bitcoin-${VERSION}-linux-gitian.zip * - mv bitcoin-${VERSION}-linux-gitian.zip ../../ - popd - ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml - pushd build/out - zip -r bitcoin-${VERSION}-win32-gitian.zip * - mv bitcoin-${VERSION}-win32-gitian.zip ../../ - popd - - Build output expected: - 1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip) - 2. windows 32-bit binary, installer + source (bitcoin-${VERSION}-win32-gitian.zip) - 3. Gitian signatures (in gitian.sigs/${VERSION}[-win32]/(your gitian key)/ - -* repackage gitian builds for release as stand-alone zip/tar/installer exe - - * Linux .tar.gz: - unzip bitcoin-${VERSION}-linux-gitian.zip -d bitcoin-${VERSION}-linux - tar czvf bitcoin-${VERSION}-linux.tar.gz bitcoin-${VERSION}-linux - rm -rf bitcoin-${VERSION}-linux - - * Windows .zip and setup.exe: - unzip bitcoin-${VERSION}-win32-gitian.zip -d bitcoin-${VERSION}-win32 - mv bitcoin-${VERSION}-win32/bitcoin-*-setup.exe . - zip -r bitcoin-${VERSION}-win32.zip bitcoin-${VERSION}-win32 - rm -rf bitcoin-${VERSION}-win32 - -* perform Mac build - OSX binaries are created by Gavin Andresen on a 32-bit, OSX 10.6 machine. - - qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro - make - export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files - T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) - python2.7 share/qt/clean_mac_info_plist.py - python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist - - Build output expected: - Bitcoin-Qt.dmg - -* Code-sign Windows -setup.exe (in a Windows virtual machine) and - OSX Bitcoin-Qt.app (Note: only Gavin has the code-signing keys currently) - -* upload builds to SourceForge - -* create SHA256SUMS for builds, and PGP-sign it - -* update bitcoin.org version - make sure all OS download links go to the right versions - -* update forum version - -* update wiki download links - -* update wiki changelog: https://en.bitcoin.it/wiki/Changelog - -* Commit your signature to gitian.sigs: - pushd gitian.sigs - git add ${VERSION}/${SIGNER} - git add ${VERSION}-win32/${SIGNER} - git commit -a - git push # Assuming you can push to the gitian.sigs tree - popd - -------------------------------------------------------------------------- - -* After 3 or more people have gitian-built, repackage gitian-signed zips: - - * From a directory containing bitcoin source, gitian.sigs and gitian zips - export VERSION=0.5.1 - mkdir bitcoin-${VERSION}-linux-gitian - pushd bitcoin-${VERSION}-linux-gitian - unzip ../bitcoin-${VERSION}-linux-gitian.zip - mkdir gitian - cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ - for signer in $(ls ../gitian.sigs/${VERSION}/); do - cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert - cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig - done - zip -r bitcoin-${VERSION}-linux-gitian.zip * - cp bitcoin-${VERSION}-linux-gitian.zip ../ - popd - mkdir bitcoin-${VERSION}-win32-gitian - pushd bitcoin-${VERSION}-win32-gitian - unzip ../bitcoin-${VERSION}-win32-gitian.zip - mkdir gitian - cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ - for signer in $(ls ../gitian.sigs/${VERSION}-win32/); do - cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert - cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig - done - zip -r bitcoin-${VERSION}-win32-gitian.zip * - cp bitcoin-${VERSION}-win32-gitian.zip ../ - popd - - * Upload gitian zips to SourceForge diff --git a/doc/unit-tests.txt b/doc/unit-tests.md similarity index 55% rename from doc/unit-tests.txt rename to doc/unit-tests.md index a12786512..d6fb2d8e2 100644 --- a/doc/unit-tests.txt +++ b/doc/unit-tests.md @@ -1,18 +1,19 @@ Compiling/running bitcoind unit tests ------------------------------------ -bitcoind unit tests are in the src/test/ directory; they +bitcoind unit tests are in the `src/test/` directory; they use the Boost::Test unit-testing framework. To compile and run the tests: -cd src -make -f makefile.unix test_bitcoin # Replace makefile.unix if you're not on unix -./test_bitcoin # Runs the unit tests + + cd src + make -f makefile.unix test_bitcoin # Replace makefile.unix if you're not on unix + ./test_bitcoin # Runs the unit tests If all tests succeed the last line of output will be: -*** No errors detected +`*** No errors detected` -To add more tests, add BOOST_AUTO_TEST_CASE functions to the existing +To add more tests, add `BOOST_AUTO_TEST_CASE` functions to the existing .cpp files in the test/ directory or add new .cpp files that implement new BOOST_AUTO_TEST_SUITE sections (the makefiles are set up to add test/*.cpp to test_bitcoin automatically). @@ -25,9 +26,10 @@ Bitcoin-Qt unit tests are in the src/qt/test/ directory; they use the Qt unit-testing framework. To compile and run the tests: -qmake bitcoin-qt.pro BITCOIN_QT_TEST=1 -make -./bitcoin-qt_test -To add more tests, add them to the src/qt/test/ directory, -the src/qt/test/test_main.cpp file, and bitcoin-qt.pro. + qmake bitcoin-qt.pro BITCOIN_QT_TEST=1 + make + ./bitcoin-qt_test + +To add more tests, add them to the `src/qt/test/` directory, +the `src/qt/test/test_main.cpp` file, and bitcoin-qt.pro. From 2ec349bc420d7f4541bf91acf8b830377a1421f3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 21 May 2013 02:36:48 +0200 Subject: [PATCH 44/69] CreateNewBlock performance improvements --- src/main.cpp | 28 +++++++++------------------- src/main.h | 2 +- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e2bed5278..2d22541ba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1342,7 +1342,7 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const return nSigOps; } -bool CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const +void CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const { // mark inputs spent if (!IsCoinBase()) { @@ -1356,8 +1356,6 @@ bool CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, // add outputs assert(inputs.SetCoins(txhash, CCoins(*this, nHeight))); - - return true; } bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const @@ -1683,8 +1681,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi } CTxUndo txundo; - if (!tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i))) - return error("ConnectBlock() : UpdateInputs failed"); + tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i)); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); @@ -4233,8 +4230,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Read prev transaction - CCoins coins; - if (!view.GetCoins(txin.prevout.hash, coins)) + if (!view.HaveCoins(txin.prevout.hash)) { // This should never happen; all transactions in the memory // pool should connect to either transactions in the chain @@ -4261,6 +4257,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue; continue; } + const CCoins &coins = view.GetCoins(txin.prevout.hash); int64 nValueIn = coins.vout[txin.prevout.n].nValue; nTotalIn += nValueIn; @@ -4308,9 +4305,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); vecPriority.pop_back(); - // second layer cached modifications just for this transaction - CCoinsViewCache viewTemp(view, true); - // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= nBlockMaxSize) @@ -4335,26 +4329,22 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); } - if (!tx.HaveInputs(viewTemp)) + if (!tx.HaveInputs(view)) continue; - int64 nTxFees = tx.GetValueIn(viewTemp)-tx.GetValueOut(); + int64 nTxFees = tx.GetValueIn(view)-tx.GetValueOut(); - nTxSigOps += tx.GetP2SHSigOpCount(viewTemp); + nTxSigOps += tx.GetP2SHSigOpCount(view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; CValidationState state; - if (!tx.CheckInputs(state, viewTemp, true, SCRIPT_VERIFY_P2SH)) + if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH)) continue; CTxUndo txundo; uint256 hash = tx.GetHash(); - if (!tx.UpdateCoins(state, viewTemp, txundo, pindexPrev->nHeight+1, hash)) - continue; - - // push changes from the second layer cache to the first one - viewTemp.Flush(); + tx.UpdateCoins(state, view, txundo, pindexPrev->nHeight+1, hash); // Added pblock->vtx.push_back(tx); diff --git a/src/main.h b/src/main.h index cba8421c8..8e71e66cc 100644 --- a/src/main.h +++ b/src/main.h @@ -659,7 +659,7 @@ public: std::vector *pvChecks = NULL) const; // Apply the effects of this transaction on the UTXO set represented by view - bool UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const; + void UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const; // Context-independent validity checks bool CheckTransaction(CValidationState &state) const; From e175c16f5b4d872da7b152bd7875be3e945b33e5 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 14 May 2013 09:52:02 +0200 Subject: [PATCH 45/69] Add a few data-driven tests for SIGHASH_ANYONECANPAY --- src/test/data/tx_invalid.json | 7 ++++++- src/test/data/tx_valid.json | 12 +++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index f01ee06cf..81e77b7df 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -60,5 +60,10 @@ ["Null txin"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true] +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true], + +["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 5528ae724..c6099246f 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -67,5 +67,15 @@ ["Coinbase of size 100"], ["Note the input is just required to make the tester happy"], [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true] +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], + +["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true], + +["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", true] ] From a680b095b68130579289f3b9282863b940239f12 Mon Sep 17 00:00:00 2001 From: Michael Ford Date: Wed, 22 May 2013 12:34:18 +0800 Subject: [PATCH 46/69] Update links in build-osx.md Add link to Github for Mac Update link to HomeBrew --- doc/build-osx.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/build-osx.md b/doc/build-osx.md index d9aa779f8..1fc33b15a 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -47,13 +47,13 @@ be done in `Xcode > Preferences > Downloads > Components` and generally must be re-done or updated every time Xcode is updated. There's an assumption that you already have `git` installed, as well. If -not, it's the path of least resistance to install Github for Mac +not, it's the path of least resistance to install [Github for Mac](https://mac.github.com/) (OS X 10.7+) or [Git for OS X](https://code.google.com/p/git-osx-installer/). It is also available via Homebrew or MacPorts. -You will also need to install [Homebrew](http://mxcl.github.com/homebrew/) -or [MacPorts](http://www.macports.org/) in order to install library +You will also need to install [Homebrew](http://mxcl.github.io/homebrew/) +or [MacPorts](https://www.macports.org/) in order to install library dependencies. It's largely a religious decision which to choose, but, as of December 2012, MacPorts is a little easier because you can just install the dependencies immediately - no other work required. If you're unsure, read From 5ada394edfac892f6fdc650ed904f121999b3407 Mon Sep 17 00:00:00 2001 From: Warren Togami Date: Wed, 22 May 2013 00:20:07 -1000 Subject: [PATCH 47/69] gitian deps-win32.yml needs psmisc package for killall to end the build --- contrib/gitian-descriptors/deps-win32.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/gitian-descriptors/deps-win32.yml b/contrib/gitian-descriptors/deps-win32.yml index 106bd06a9..90f4c6c4b 100644 --- a/contrib/gitian-descriptors/deps-win32.yml +++ b/contrib/gitian-descriptors/deps-win32.yml @@ -10,6 +10,7 @@ packages: - "zip" - "faketime" - "wine" +- "psmisc" reference_datetime: "2011-01-30 00:00:00" remotes: [] files: From 95c7db3dbf4012dd02e5f1f30e6d982341facaa6 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 22 May 2013 20:58:53 +0200 Subject: [PATCH 48/69] More bestblock records in wallets Write bestblock records in wallets: * Every 20160 blocks synced, no matter what (before: none during IBD) * Every 144 blocks after IBD (before: for every block, slow) * When creating a new wallet * At shutdown This should result in far fewer spurious rescans. --- src/init.cpp | 3 +++ src/main.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index d619cb412..ebd9dee7b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -100,6 +100,7 @@ void Shutdown() StopNode(); { LOCK(cs_main); + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); if (pblocktree) pblocktree->Flush(); if (pcoinsTip) @@ -998,6 +999,8 @@ bool AppInit2(boost::thread_group& threadGroup) if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) strErrors << _("Cannot write default address") << "\n"; } + + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); } printf("%s", strErrors.str().c_str()); diff --git a/src/main.cpp b/src/main.cpp index 2d22541ba..b7efac53b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1870,7 +1870,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) } // Update best block in wallet (so we can detect restored wallets) - if (!fIsInitialDownload) + if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) { const CBlockLocator locator(pindexNew); ::SetBestChain(locator); From 36dc41f4273c59e570978c603e48bbec43f3d0a1 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Wed, 22 May 2013 17:20:17 -0400 Subject: [PATCH 49/69] doc/README was replaced by README.md --- bitcoin-qt.pro | 1 - contrib/gitian-descriptors/gitian.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index a217836df..bb27170cb 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -335,7 +335,6 @@ QMAKE_EXTRA_COMPILERS += TSQM OTHER_FILES += README.md \ doc/*.rst \ doc/*.txt \ - doc/README \ src/qt/res/bitcoin-qt.rc \ src/test/*.cpp \ src/test/*.h \ diff --git a/contrib/gitian-descriptors/gitian.yml b/contrib/gitian-descriptors/gitian.yml index 8243c5c30..195d0e36f 100644 --- a/contrib/gitian-descriptors/gitian.yml +++ b/contrib/gitian-descriptors/gitian.yml @@ -43,7 +43,7 @@ script: | cd bitcoin mkdir -p $OUTDIR/src git archive HEAD | tar -x -C $OUTDIR/src - cp $OUTDIR/src/doc/README $OUTDIR + cp $OUTDIR/src/doc/README.md $OUTDIR cp $OUTDIR/src/COPYING $OUTDIR cd src make -f makefile.unix STATIC=1 OPENSSL_INCLUDE_PATH="$INSTDIR/include" OPENSSL_LIB_PATH="$INSTDIR/lib" $MAKEOPTS bitcoind USE_UPNP=0 DEBUGFLAGS= From 6a2da2ba96fd2a5db0e1ba449b2ff39564f996e5 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Thu, 23 May 2013 08:39:31 +0200 Subject: [PATCH 50/69] translations update 2013-05-23 - integrates current translations from Transifex --- src/qt/locale/bitcoin_ar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 028080d54..741a25a4d 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -38,7 +38,7 @@ This product includes software developed by the OpenSSL Project for use in the O Address Book - كتاب العنوانين + دفتر العناوين From 36e826cea14585f68d5c363a82c1a887a779e130 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 23 May 2013 14:13:05 -0400 Subject: [PATCH 51/69] Clean up mining CReserveKey to prevent crash at shutdown Fixes issue#2687 --- src/bitcoinrpc.cpp | 9 +++++++++ src/bitcoinrpc.h | 2 ++ src/rpcmining.cpp | 9 +++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index a9b73fd5a..2c4744a57 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -30,6 +30,10 @@ using namespace boost; using namespace boost::asio; using namespace json_spirit; +// Key used by getwork/getblocktemplate miners. +// Allocated in StartRPCThreads, free'd in StopRPCThreads +CReserveKey* pMiningKey = NULL; + static std::string strRPCUserColonPass; // These are created by StartRPCThreads, destroyed in StopRPCThreads @@ -722,6 +726,9 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptorstop(); diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 315fd9238..cf5b13798 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -11,6 +11,7 @@ #include class CBlockIndex; +class CReserveKey; #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" @@ -122,6 +123,7 @@ public: }; extern const CRPCTable tableRPC; +extern CReserveKey* pMiningKey; extern int64 nWalletUnlockTime; extern int64 AmountFromValue(const json_spirit::Value& value); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index fddda8b5f..b8b745963 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -104,7 +104,6 @@ Value getwork(const Array& params, bool fHelp) typedef map > mapNewBlock_t; static mapNewBlock_t mapNewBlock; // FIXME: thread safety static vector vNewBlockTemplate; - static CReserveKey reservekey(pwalletMain); if (params.size() == 0) { @@ -134,7 +133,7 @@ Value getwork(const Array& params, bool fHelp) nStart = GetTime(); // Create new block - pblocktemplate = CreateNewBlock(reservekey); + pblocktemplate = CreateNewBlock(*pMiningKey); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); vNewBlockTemplate.push_back(pblocktemplate); @@ -192,7 +191,7 @@ Value getwork(const Array& params, bool fHelp) pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - return CheckWork(pblock, *pwalletMain, reservekey); + return CheckWork(pblock, *pwalletMain, *pMiningKey); } } @@ -243,8 +242,6 @@ Value getblocktemplate(const Array& params, bool fHelp) if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks..."); - static CReserveKey reservekey(pwalletMain); - // Update block static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; @@ -267,7 +264,7 @@ Value getblocktemplate(const Array& params, bool fHelp) delete pblocktemplate; pblocktemplate = NULL; } - pblocktemplate = CreateNewBlock(reservekey); + pblocktemplate = CreateNewBlock(*pMiningKey); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); From b4b017059514ed0157877984363ed94f5ab098e9 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 10 May 2013 22:20:51 +0200 Subject: [PATCH 52/69] osx: make use of the 10.8+ user notification center to display growl like notifications - if 10.8, use user notification center, if <10.8, use growl Signed-off-by: Jonas Schnelli --- bitcoin-qt.pro | 4 +- src/qt/macnotificationhandler.h | 25 ++++++++++++ src/qt/macnotificationhandler.mm | 65 ++++++++++++++++++++++++++++++++ src/qt/notificator.cpp | 43 ++++++++++++++------- src/qt/notificator.h | 12 +++--- 5 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 src/qt/macnotificationhandler.h create mode 100644 src/qt/macnotificationhandler.mm diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index a217836df..f41da5306 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -393,8 +393,8 @@ win32:!contains(MINGW_THREAD_BUGFIX, 0) { DEFINES += _FILE_OFFSET_BITS=64 } -macx:HEADERS += src/qt/macdockiconhandler.h -macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm +macx:HEADERS += src/qt/macdockiconhandler.h src/qt/macnotificationhandler.h +macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm src/qt/macnotificationhandler.mm macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 macx:ICON = src/qt/res/icons/bitcoin.icns diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h new file mode 100644 index 000000000..cd8064c61 --- /dev/null +++ b/src/qt/macnotificationhandler.h @@ -0,0 +1,25 @@ +#ifndef MACNOTIFICATIONHANDLER_H +#define MACNOTIFICATIONHANDLER_H +#include + +/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl). + */ +class MacNotificationHandler : public QObject +{ + Q_OBJECT + +public: + /** shows a 10.8+ UserNotification in the UserNotificationCenter + */ + void showNotification(const QString &title, const QString &text); + + /** executes AppleScript */ + void sendAppleScript(const QString &script); + + /** check if OS can handle UserNotifications */ + bool hasUserNotificationCenterSupport(void); + static MacNotificationHandler *instance(); +}; + + +#endif // MACNOTIFICATIONHANDLER_H diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm new file mode 100644 index 000000000..8bb9b887a --- /dev/null +++ b/src/qt/macnotificationhandler.mm @@ -0,0 +1,65 @@ +#include "macnotificationhandler.h" + +#undef slots +#include + +void MacNotificationHandler::showNotification(const QString &title, const QString &text) +{ + // check if users OS has support for NSUserNotification + if(this->hasUserNotificationCenterSupport()) { + // okay, seems like 10.8+ + QByteArray utf8 = title.toUtf8(); + char* cString = (char *)utf8.constData(); + NSString *titleMac = [[NSString alloc] initWithUTF8String:cString]; + + utf8 = text.toUtf8(); + cString = (char *)utf8.constData(); + NSString *textMac = [[NSString alloc] initWithUTF8String:cString]; + + // do everything weak linked (because we will keep <10.8 compatibility) + id userNotification = [[NSClassFromString(@"NSUserNotification") alloc] init]; + [userNotification performSelector:@selector(setTitle:) withObject:titleMac]; + [userNotification performSelector:@selector(setInformativeText:) withObject:textMac]; + + id notificationCenterInstance = [NSClassFromString(@"NSUserNotificationCenter") performSelector:@selector(defaultUserNotificationCenter)]; + [notificationCenterInstance performSelector:@selector(deliverNotification:) withObject:userNotification]; + + [titleMac release]; + [textMac release]; + [userNotification release]; + } +} + +// sendAppleScript just take a QString and executes it as apple script +void MacNotificationHandler::sendAppleScript(const QString &script) +{ + QByteArray utf8 = script.toUtf8(); + char* cString = (char *)utf8.constData(); + NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString]; + + NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple]; + NSDictionary *err = nil; + [as executeAndReturnError:&err]; + [as release]; + [scriptApple release]; +} + +bool MacNotificationHandler::hasUserNotificationCenterSupport(void) +{ + Class possibleClass = NSClassFromString(@"NSUserNotificationCenter"); + + // check if users OS has support for NSUserNotification + if(possibleClass!=nil) { + return true; + } + return false; +} + + +MacNotificationHandler *MacNotificationHandler::instance() +{ + static MacNotificationHandler *s_instance = NULL; + if (!s_instance) + s_instance = new MacNotificationHandler(); + return s_instance; +} diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 397e7aa4a..7cfaef607 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -18,7 +18,7 @@ #ifdef Q_OS_MAC #include -extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); +#include "macnotificationhandler.h" #endif // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128 @@ -47,19 +47,25 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, } #endif #ifdef Q_OS_MAC - // Check if Growl is installed (based on Qt's tray icon implementation) - CFURLRef cfurl; - OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); - if (status != kLSApplicationNotFoundErr) { - CFBundleRef bundle = CFBundleCreate(0, cfurl); - if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { - if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) - mode = Growl13; - else - mode = Growl12; + // check if users OS has support for NSUserNotification + if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) { + mode = UserNotificationCenter; + } + else { + // Check if Growl is installed (based on Qt's tray icon implementation) + CFURLRef cfurl; + OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); + if (status != kLSApplicationNotFoundErr) { + CFBundleRef bundle = CFBundleCreate(0, cfurl); + if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { + if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) + mode = Growl13; + else + mode = Growl12; + } + CFRelease(cfurl); + CFRelease(bundle); } - CFRelease(cfurl); - CFRelease(bundle); } #endif } @@ -269,8 +275,14 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te quotedTitle.replace("\\", "\\\\").replace("\"", "\\"); quotedText.replace("\\", "\\\\").replace("\"", "\\"); QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp"); - qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0); + MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp)); } + +void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) { + // icon is not supported by the user notification center yet. OSX will use the app icon. + MacNotificationHandler::instance()->showNotification(title, text); +} + #endif void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) @@ -286,6 +298,9 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c notifySystray(cls, title, text, icon, millisTimeout); break; #ifdef Q_OS_MAC + case UserNotificationCenter: + notifyMacUserNotificationCenter(cls, title, text, icon); + break; case Growl12: case Growl13: notifyGrowl(cls, title, text, icon); diff --git a/src/qt/notificator.h b/src/qt/notificator.h index d20673abb..d1fe37fea 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -46,11 +46,12 @@ public slots: private: QWidget *parent; enum Mode { - None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ - Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ - Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ - Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ + None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ + Freedesktop, /**< Use DBus org.freedesktop.Notifications */ + QSystemTray, /**< Use QSystemTray::showMessage */ + Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ + Growl13, /**< Use the Growl 1.3 notification system (Mac only) */ + UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; Mode mode; @@ -63,6 +64,7 @@ private: void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #ifdef Q_OS_MAC void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon); + void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon); #endif }; From 03f498080a813850e1a3addf2c555450aa5e65c1 Mon Sep 17 00:00:00 2001 From: Robert Backhaus Date: Fri, 24 May 2013 23:40:51 +1000 Subject: [PATCH 53/69] Explictly cast calculation to int, to allow std::max to work. --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index ebd9dee7b..3eb090ac0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -530,7 +530,7 @@ bool AppInit2(boost::thread_group& threadGroup) // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind"), 1); nMaxConnections = GetArg("-maxconnections", 125); - nMaxConnections = std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS), 0); + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); if (nFD < MIN_CORE_FILEDESCRIPTORS) return InitError(_("Not enough file descriptors available.")); From 65ec9eab2bf1aea0bd580e1d972f54163b58b332 Mon Sep 17 00:00:00 2001 From: Robert Backhaus Date: Fri, 24 May 2013 23:45:08 +1000 Subject: [PATCH 54/69] Explicitly #include stdarg.h, for access to va_list --- src/util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util.h b/src/util.h index 3d2536450..51a694483 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,8 @@ #include "uint256.h" +#include + #ifndef WIN32 #include #include From f0d8a52cc039cda77730047db2443fbec016f852 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 24 May 2013 11:10:53 -0400 Subject: [PATCH 55/69] Replace repeated GetBoolArg() calls with Checkpoint::fEnabled variable set once at init time. --- src/checkpoints.cpp | 8 +++++--- src/checkpoints.h | 2 ++ src/init.cpp | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 9e8e0f702..7643ec5df 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -28,6 +28,8 @@ namespace Checkpoints double fTransactionsPerDay; }; + bool fEnabled = true; + // What makes a good checkpoint block? // + Is surrounded by blocks with reasonable timestamps // (no blocks before with a timestamp after, none after with @@ -74,7 +76,7 @@ namespace Checkpoints bool CheckBlock(int nHeight, const uint256& hash) { - if (!GetBoolArg("-checkpoints", true)) + if (!fEnabled) return true; const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; @@ -117,7 +119,7 @@ namespace Checkpoints int GetTotalBlocksEstimate() { - if (!GetBoolArg("-checkpoints", true)) + if (!fEnabled) return 0; const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; @@ -127,7 +129,7 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) { - if (!GetBoolArg("-checkpoints", true)) + if (!fEnabled) return NULL; const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; diff --git a/src/checkpoints.h b/src/checkpoints.h index 3d5688555..a49a908a3 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -24,6 +24,8 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex); double GuessVerificationProgress(CBlockIndex *pindex); + + extern bool fEnabled; } #endif diff --git a/src/init.cpp b/src/init.cpp index ebd9dee7b..6dafcc4af 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -10,6 +10,7 @@ #include "init.h" #include "util.h" #include "ui_interface.h" +#include "checkpoints.h" #include #include @@ -493,6 +494,7 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 2: parameter interactions fTestNet = GetBoolArg("-testnet"); + Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); if (mapArgs.count("-bind")) { // when specifying an explicit binding address, you want to listen on it From 8ab6d0a568013530c2df105fcc7c8dbdc894f74e Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Fri, 24 May 2013 15:46:00 -0400 Subject: [PATCH 56/69] All-resolution pixmap, to make win32 builds determisitic again --- share/pixmaps/bitcoin.ico | Bin 353118 -> 68756 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico index 48a9822a46abd9da41d10f44dae5c34ba405afcc..f5480f41616a81cc3b65d0625f4f5e6f01a2f861 100644 GIT binary patch delta 45176 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 literal 353118 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 %`k;G1CUE=#-w*I|gTelQ&1ujd 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 Date: Fri, 24 May 2013 15:52:52 -0400 Subject: [PATCH 57/69] Fix crash-at-shutdown if exiting before initializing wallet --- src/init.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index ebd9dee7b..59bf32eca 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -100,7 +100,8 @@ void Shutdown() StopNode(); { LOCK(cs_main); - pwalletMain->SetBestChain(CBlockLocator(pindexBest)); + if (pwalletMain) + pwalletMain->SetBestChain(CBlockLocator(pindexBest)); if (pblocktree) pblocktree->Flush(); if (pcoinsTip) From ef9acc5124459b111d8643323a71d8198d0eaae8 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Fri, 24 May 2013 16:11:44 -0400 Subject: [PATCH 58/69] Bump build number to 0.8.2.2 for v0.8.2rc3 --- share/setup.nsi | 2 +- src/clientversion.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/setup.nsi b/share/setup.nsi index 3715b4620..d5f2ffc3f 100644 --- a/share/setup.nsi +++ b/share/setup.nsi @@ -51,7 +51,7 @@ CRCCheck on XPStyle on BrandingText " " ShowInstDetails show -VIProductVersion 0.8.2.1 +VIProductVersion 0.8.2.2 VIAddVersionKey ProductName Bitcoin VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey CompanyName "${COMPANY}" diff --git a/src/clientversion.h b/src/clientversion.h index aabab4c72..e4fd6a69f 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -9,7 +9,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 8 #define CLIENT_VERSION_REVISION 2 -#define CLIENT_VERSION_BUILD 1 +#define CLIENT_VERSION_BUILD 2 // Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true From 98ab2b5a265e4794d6a9d22212d992bfd1f9c1f1 Mon Sep 17 00:00:00 2001 From: Robert Backhaus Date: Wed, 29 May 2013 10:33:36 +1000 Subject: [PATCH 59/69] Don't attempt to resize vector to negative size. --- src/db.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/db.cpp b/src/db.cpp index 3133d99bf..fd4c67d55 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -541,6 +541,8 @@ bool CAddrDB::Read(CAddrMan& addr) // use file size to size memory buffer int fileSize = GetFilesize(filein); int dataSize = fileSize - sizeof(uint256); + //Don't try to resize to a negative number if file is small + if ( dataSize < 0 ) dataSize = 0; vector vchData; vchData.resize(dataSize); uint256 hashIn; From 8c8132be73b680d04b9f6dff9dee0ae277c1bebb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 30 May 2013 04:43:51 +0200 Subject: [PATCH 60/69] Prepare for 0.9 merge window --- doc/release-notes.md | 77 -------------------------------------------- src/clientversion.h | 6 ++-- 2 files changed, 3 insertions(+), 80 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 0e0b04bca..acaeef1d6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,80 +1,3 @@ (note: this is a temporary file, to be added-to by anybody, and deleted at release time) -Fee Policy changes ------------------- - -The default fee for low-priority transactions is lowered from 0.0005 BTC -(for each 1,000 bytes in the transaction; an average transaction is -about 500 bytes) to 0.0001 BTC. - -Payments (transaction outputs) of 0.543 times the minimum relay fee -(0.00005430 BTC) are now considered 'non-standard', because storing them -costs the network more than they are worth and spending them will usually -cost their owner more in transaction fees than they are worth. - -Non-standard transactions are not relayed across the network, are not included -in blocks by most miners, and will not show up in your wallet until they are -included in a block. - -The default fee policy can be overridden using the -mintxfee and -minrelaytxfee -command-line options, but note that we intend to replace the hard-coded fees -with code that automatically calculates and suggests appropriate fees in the -0.9 release and note that if you set a fee policy significantly different from -the rest of the network your transactions may never confirm. - -Bitcoin-Qt changes ------------------- - -- New icon and splash screen -- Improve reporting of synchronization process -- Remove hardcoded fee recommendations -- Improve metadata of executable on MacOSX and Windows -- Move export button to individual tabs instead of toolbar -- Add "send coins" command to context menu in address book -- Add "copy txid" command to copy transaction IDs from transaction overview -- Save & restore window size and position when showing & hiding window -- New translations: Arabic (ar), Bosnian (bs), Catalan (ca), Welsh (cy), Esperanto (eo), Interlingua (la), Latvian (lv) and many improvements to current translations - -MacOSX: - -- OSX support for click-to-pay (bitcoin:) links -- Fix GUI disappearing problem on MacOSX (issue #1522) - -Linux/Unix: - -- Copy addresses to middle-mouse-button clipboard - - -Command-line options --------------------- - -* `-walletnotify` will call a command on receiving transactions that affect the wallet. -* `-alertnotify` will call a command on receiving an alert from the network. -* `-par` now takes a negative number, to leave a certain amount of cores free. - -JSON-RPC API changes --------------------- - -* `listunspent` now lists account and address infromation. -* `getinfo` now also returns the time adjustment estimated from your peers. -* `getpeerinfo` now returns bytessent, bytesrecv and syncnode. -* `gettxoutsetinfo` returns statistics about the unspent transaction output database. -* `gettxout` returns information about a specific unspent transaction output. - - -Networking changes ------------------- - -* Significant changes to the networking code, reducing latency and memory consumption. -* Avoid initial block download stalling. -* Remove IRC seeding support. -* Performance tweaks. -* Added testnet DNS seeds. - -Wallet compatibility/rescuing ------------------------------ - -* Cases where wallets cannot be opened in another version/installation should be reduced. -* `-salvagewallet` now works for encrypted wallets. - diff --git a/src/clientversion.h b/src/clientversion.h index e4fd6a69f..30c0c4072 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -8,11 +8,11 @@ // These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 8 -#define CLIENT_VERSION_REVISION 2 -#define CLIENT_VERSION_BUILD 2 +#define CLIENT_VERSION_REVISION 99 +#define CLIENT_VERSION_BUILD 0 // Set to true for release, false for prerelease or test build -#define CLIENT_VERSION_IS_RELEASE true +#define CLIENT_VERSION_IS_RELEASE false // Copyright year (2009-this) // Todo: update this when changing our copyright comments in the source From 5d891489ab7828ad8db15e85bb63e2f13f021a6a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 30 Apr 2013 21:56:04 +0200 Subject: [PATCH 61/69] Make CPubKey statically allocated --- src/hash.h | 11 ++++-- src/key.cpp | 14 ++++---- src/key.h | 85 +++++++++++++++++++++++++++++++++++++++-------- src/rpcwallet.cpp | 2 +- src/script.cpp | 5 +-- src/script.h | 6 ++-- src/util.h | 3 +- 7 files changed, 98 insertions(+), 28 deletions(-) diff --git a/src/hash.h b/src/hash.h index eaa1780c0..536ab7116 100644 --- a/src/hash.h +++ b/src/hash.h @@ -105,15 +105,22 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL return ss.GetHash(); } -inline uint160 Hash160(const std::vector& vch) +template +inline uint160 Hash160(const T1 pbegin, const T1 pend) { + static unsigned char pblank[1]; uint256 hash1; - SHA256(&vch[0], vch.size(), (unsigned char*)&hash1); + SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); uint160 hash2; RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); return hash2; } +inline uint160 Hash160(const std::vector& vch) +{ + return Hash160(vch.begin(), vch.end()); +} + unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash); #endif diff --git a/src/key.cpp b/src/key.cpp index 75114c6af..a99363c12 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -258,11 +258,11 @@ CPrivKey CKey::GetPrivKey() const bool CKey::SetPubKey(const CPubKey& vchPubKey) { - const unsigned char* pbegin = &vchPubKey.vchPubKey[0]; - if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size())) + const unsigned char* pbegin = vchPubKey.begin(); + if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) { fSet = true; - if (vchPubKey.vchPubKey.size() == 33) + if (vchPubKey.size() == 33) SetCompressedPubKey(); return true; } @@ -276,11 +276,13 @@ CPubKey CKey::GetPubKey() const int nSize = i2o_ECPublicKey(pkey, NULL); if (!nSize) throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); - std::vector vchPubKey(nSize, 0); - unsigned char* pbegin = &vchPubKey[0]; + assert(nSize <= 65); + CPubKey ret; + unsigned char *pbegin = ret.begin(); if (i2o_ECPublicKey(pkey, &pbegin) != nSize) throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); - return CPubKey(vchPubKey); + assert((int)ret.size() == nSize); + return ret; } bool CKey::Sign(uint256 hash, std::vector& vchSig) diff --git a/src/key.h b/src/key.h index 4da16b9cd..1b122112f 100644 --- a/src/key.h +++ b/src/key.h @@ -63,38 +63,95 @@ public: /** An encapsulated public key. */ class CPubKey { private: - std::vector vchPubKey; + unsigned char vch[65]; + + unsigned int static GetLen(unsigned char chHeader) { + if (chHeader == 2 || chHeader == 3) + return 33; + if (chHeader == 4 || chHeader == 6 || chHeader == 7) + return 65; + return 0; + } + + unsigned char *begin() { + return vch; + } + friend class CKey; public: - CPubKey() { } - CPubKey(const std::vector &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } - friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } - friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } - friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; } + CPubKey() { vch[0] = 0xFF; } - IMPLEMENT_SERIALIZE( - READWRITE(vchPubKey); - ) + CPubKey(const std::vector &vchPubKeyIn) { + int len = vchPubKeyIn.empty() ? 0 : GetLen(vchPubKeyIn[0]); + if (len) { + memcpy(vch, &vchPubKeyIn[0], len); + } else { + vch[0] = 0xFF; + } + } + + unsigned int size() const { + return GetLen(vch[0]); + } + + const unsigned char *begin() const { + return vch; + } + + const unsigned char *end() const { + return vch+size(); + } + + friend bool operator==(const CPubKey &a, const CPubKey &b) { return memcmp(a.vch, b.vch, a.size()) == 0; } + friend bool operator!=(const CPubKey &a, const CPubKey &b) { return memcmp(a.vch, b.vch, a.size()) != 0; } + friend bool operator<(const CPubKey &a, const CPubKey &b) { + return a.vch[0] < b.vch[0] || + (a.vch[0] == b.vch[0] && memcmp(a.vch+1, b.vch+1, a.size() - 1) < 0); + } + + unsigned int GetSerializeSize(int nType, int nVersion) const { + return size() + 1; + } + + template void Serialize(Stream &s, int nType, int nVersion) const { + unsigned int len = size(); + ::Serialize(s, VARINT(len), nType, nVersion); + s.write((char*)vch, len); + } + + template void Unserialize(Stream &s, int nType, int nVersion) { + unsigned int len; + ::Unserialize(s, VARINT(len), nType, nVersion); + if (len <= 65) { + s.read((char*)vch, len); + } else { + // invalid pubkey + vch[0] = 0xFF; + char dummy; + while (len--) + s.read(&dummy, 1); + } + } CKeyID GetID() const { - return CKeyID(Hash160(vchPubKey)); + return CKeyID(Hash160(vch, vch+size())); } uint256 GetHash() const { - return Hash(vchPubKey.begin(), vchPubKey.end()); + return Hash(vch, vch+size()); } bool IsValid() const { - return vchPubKey.size() == 33 || vchPubKey.size() == 65; + return size() > 0; } bool IsCompressed() const { - return vchPubKey.size() == 33; + return size() == 33; } std::vector Raw() const { - return vchPubKey; + return std::vector(vch, vch+size()); } }; diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 5fd400c6b..64ee39081 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1445,7 +1445,7 @@ public: CPubKey vchPubKey; pwalletMain->GetPubKey(keyID, vchPubKey); obj.push_back(Pair("isscript", false)); - obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw()))); + obj.push_back(Pair("pubkey", HexStr(vchPubKey))); obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); return obj; } diff --git a/src/script.cpp b/src/script.cpp index 90066efd3..7e1d5785e 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1895,10 +1895,11 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector vchKey = key.Raw(); - return (*this) << vchKey; + assert(key.size() < OP_PUSHDATA1); + insert(end(), (unsigned char)key.size()); + insert(end(), key.begin(), key.end()); + return *this; } CScript& operator<<(const CBigNum& b) diff --git a/src/util.h b/src/util.h index 51a694483..b922545b9 100644 --- a/src/util.h +++ b/src/util.h @@ -300,7 +300,8 @@ std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) return rv; } -inline std::string HexStr(const std::vector& vch, bool fSpaces=false) +template +inline std::string HexStr(const T& vch, bool fSpaces=false) { return HexStr(vch.begin(), vch.end(), fSpaces); } From dfa23b94c24aae6466152fccbe896ba5dc0e97b4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 1 May 2013 06:52:05 +0200 Subject: [PATCH 62/69] CSecret/CKey -> CKey/CPubKey split/refactor --- src/alert.cpp | 4 +- src/allocators.h | 9 + src/base58.h | 22 +- src/crypter.cpp | 6 +- src/crypter.h | 4 +- src/key.cpp | 497 ++++++++++++++--------------- src/key.h | 223 +++++++------ src/keystore.cpp | 86 ++--- src/keystore.h | 21 +- src/qt/signverifymessagedialog.cpp | 6 +- src/rpcdump.cpp | 19 +- src/rpcrawtransaction.cpp | 5 +- src/rpcwallet.cpp | 14 +- src/script.cpp | 33 +- src/script.h | 4 +- src/test/base58_tests.cpp | 10 +- src/test/bloom_tests.cpp | 11 +- src/test/key_tests.cpp | 92 +++--- src/test/multisig_tests.cpp | 2 +- src/test/script_P2SH_tests.cpp | 14 +- src/test/script_tests.cpp | 8 +- src/test/sigopcount_tests.cpp | 4 +- src/wallet.cpp | 18 +- src/wallet.h | 4 +- src/walletdb.cpp | 61 ++-- src/walletdb.h | 10 +- 26 files changed, 578 insertions(+), 609 deletions(-) diff --git a/src/alert.cpp b/src/alert.cpp index 4b029840d..44f4d5eec 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -144,9 +144,7 @@ bool CAlert::RelayTo(CNode* pnode) const bool CAlert::CheckSignature() const { - CKey key; - if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey))) - return error("CAlert::CheckSignature() : SetPubKey failed"); + CPubKey key(ParseHex(fTestNet ? pszTestKey : pszMainKey)); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CAlert::CheckSignature() : verify signature failed"); diff --git a/src/allocators.h b/src/allocators.h index eb2aed672..b4490ce27 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -176,6 +176,15 @@ private: {} }; +template void LockObject(const T &t) { + LockedPageManager::instance.LockRange((void*)(&t), sizeof(T)); +} + +template void UnlockObject(const T &t) { + OPENSSL_cleanse((void*)(&t), sizeof(T)); + LockedPageManager::instance.UnlockRange((void*)(&t), sizeof(T)); +} + // // Allocator that locks its contents from being paged // out of memory and clears its contents before deletion. diff --git a/src/base58.h b/src/base58.h index be8a541f6..efe3a95eb 100644 --- a/src/base58.h +++ b/src/base58.h @@ -398,21 +398,19 @@ bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { class CBitcoinSecret : public CBase58Data { public: - void SetSecret(const CSecret& vchSecret, bool fCompressed) + void SetKey(const CKey& vchSecret) { - assert(vchSecret.size() == 32); - SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size()); - if (fCompressed) + assert(vchSecret.IsValid()); + SetData(fTestNet ? 239 : 128, vchSecret.begin(), vchSecret.size()); + if (vchSecret.IsCompressed()) vchData.push_back(1); } - CSecret GetSecret(bool &fCompressedOut) + CKey GetKey() { - CSecret vchSecret; - vchSecret.resize(32); - memcpy(&vchSecret[0], &vchData[0], 32); - fCompressedOut = vchData.size() == 33; - return vchSecret; + CKey ret; + ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1); + return ret; } bool IsValid() const @@ -443,9 +441,9 @@ public: return SetString(strSecret.c_str()); } - CBitcoinSecret(const CSecret& vchSecret, bool fCompressed) + CBitcoinSecret(const CKey& vchSecret) { - SetSecret(vchSecret, fCompressed); + SetKey(vchSecret); } CBitcoinSecret() diff --git a/src/crypter.cpp b/src/crypter.cpp index a2b62a87c..32baabd67 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -100,17 +100,17 @@ bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingM } -bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_KEY_SIZE); memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); if(!cKeyCrypter.SetKey(vMasterKey, chIV)) return false; - return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext); + return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); } -bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext) +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_KEY_SIZE); diff --git a/src/crypter.h b/src/crypter.h index 6f75170ba..4134c1b49 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -101,7 +101,7 @@ public: } }; -bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); -bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext); +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); #endif diff --git a/src/key.cpp b/src/key.cpp index a99363c12..f73708199 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -2,13 +2,16 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include - #include +#include #include #include "key.h" + +// anonymous namespace with local implementation code (OpenSSL interaction) +namespace { + // Generate a private key from just the secret parameter int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) { @@ -120,293 +123,273 @@ err: return ret; } -void CKey::SetCompressedPubKey(bool fCompressed) -{ - EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); - fCompressedPubKey = true; -} +// RAII Wrapper around OpenSSL's EC_KEY +class CECKey { +private: + EC_KEY *pkey; -void CKey::Reset() -{ - fCompressedPubKey = false; - if (pkey != NULL) +public: + CECKey() { + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + assert(pkey != NULL); + } + + ~CECKey() { EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); - fSet = false; -} + } -CKey::CKey() -{ - pkey = NULL; - Reset(); -} + void GetSecretBytes(unsigned char vch[32]) const { + const BIGNUM *bn = EC_KEY_get0_private_key(pkey); + assert(bn); + int nBytes = BN_num_bytes(bn); + int n=BN_bn2bin(bn,&vch[32 - nBytes]); + assert(n == nBytes); + memset(vch, 0, 32 - nBytes); + } -CKey::CKey(const CKey& b) -{ - pkey = EC_KEY_dup(b.pkey); - if (pkey == NULL) - throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); - fSet = b.fSet; -} + void SetSecretBytes(const unsigned char vch[32]) { + BIGNUM bn; + BN_init(&bn); + assert(BN_bin2bn(vch, 32, &bn)); + assert(EC_KEY_regenerate_key(pkey, &bn)); + BN_clear_free(&bn); + } -CKey& CKey::operator=(const CKey& b) -{ - if (!EC_KEY_copy(pkey, b.pkey)) - throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); - fSet = b.fSet; - return (*this); -} + void GetPrivKey(CPrivKey &privkey) { + int nSize = i2d_ECPrivateKey(pkey, NULL); + assert(nSize); + privkey.resize(nSize); + unsigned char* pbegin = &privkey[0]; + int nSize2 = i2d_ECPrivateKey(pkey, &pbegin); + assert(nSize == nSize2); + } -CKey::~CKey() -{ - EC_KEY_free(pkey); -} - -bool CKey::IsNull() const -{ - return !fSet; -} - -bool CKey::IsCompressed() const -{ - return fCompressedPubKey; -} - -void CKey::MakeNewKey(bool fCompressed) -{ - if (!EC_KEY_generate_key(pkey)) - throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); - if (fCompressed) - SetCompressedPubKey(); - fSet = true; -} - -bool CKey::SetPrivKey(const CPrivKey& vchPrivKey) -{ - const unsigned char* pbegin = &vchPrivKey[0]; - if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) - { - // In testing, d2i_ECPrivateKey can return true - // but fill in pkey with a key that fails - // EC_KEY_check_key, so: - if (EC_KEY_check_key(pkey)) - { - fSet = true; - return true; + bool SetPrivKey(const CPrivKey &privkey) { + const unsigned char* pbegin = &privkey[0]; + if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) { + // d2i_ECPrivateKey returns true if parsing succeeds. + // This doesn't necessarily mean the key is valid. + if (EC_KEY_check_key(pkey)) + return true; } + return false; } - // If vchPrivKey data is bad d2i_ECPrivateKey() can - // leave pkey in a state where calling EC_KEY_free() - // crashes. To avoid that, set pkey to NULL and - // leak the memory (a leak is better than a crash) - pkey = NULL; - Reset(); - return false; -} -bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) -{ - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); - if (vchSecret.size() != 32) - throw key_error("CKey::SetSecret() : secret must be 32 bytes"); - BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); - if (bn == NULL) - throw key_error("CKey::SetSecret() : BN_bin2bn failed"); - if (!EC_KEY_regenerate_key(pkey,bn)) - { - BN_clear_free(bn); - throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); + void GetPubKey(CPubKey &pubkey, bool fCompressed) { + EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); + int nSize = i2o_ECPublicKey(pkey, NULL); + assert(nSize); + assert(nSize <= 65); + unsigned char c[65]; + unsigned char *pbegin = c; + int nSize2 = i2o_ECPublicKey(pkey, &pbegin); + assert(nSize == nSize2); + pubkey.Set(&c[0], &c[nSize]); } - BN_clear_free(bn); - fSet = true; - if (fCompressed || fCompressedPubKey) - SetCompressedPubKey(); - return true; -} -CSecret CKey::GetSecret(bool &fCompressed) const -{ - CSecret vchRet; - vchRet.resize(32); - const BIGNUM *bn = EC_KEY_get0_private_key(pkey); - int nBytes = BN_num_bytes(bn); - if (bn == NULL) - throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); - int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); - if (n != nBytes) - throw key_error("CKey::GetSecret(): BN_bn2bin failed"); - fCompressed = fCompressedPubKey; - return vchRet; -} + bool SetPubKey(const CPubKey &pubkey) { + const unsigned char* pbegin = pubkey.begin(); + return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size()); + } -CPrivKey CKey::GetPrivKey() const -{ - int nSize = i2d_ECPrivateKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); - CPrivKey vchPrivKey(nSize, 0); - unsigned char* pbegin = &vchPrivKey[0]; - if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); - return vchPrivKey; -} - -bool CKey::SetPubKey(const CPubKey& vchPubKey) -{ - const unsigned char* pbegin = vchPubKey.begin(); - if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) - { - fSet = true; - if (vchPubKey.size() == 33) - SetCompressedPubKey(); + bool Sign(const uint256 &hash, std::vector& vchSig) { + unsigned int nSize = ECDSA_size(pkey); + vchSig.resize(nSize); // Make sure it is big enough + assert(ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)); + vchSig.resize(nSize); // Shrink to fit actual size return true; } - pkey = NULL; - Reset(); - return false; -} -CPubKey CKey::GetPubKey() const -{ - int nSize = i2o_ECPublicKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); - assert(nSize <= 65); - CPubKey ret; - unsigned char *pbegin = ret.begin(); - if (i2o_ECPublicKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); - assert((int)ret.size() == nSize); - return ret; -} - -bool CKey::Sign(uint256 hash, std::vector& vchSig) -{ - unsigned int nSize = ECDSA_size(pkey); - vchSig.resize(nSize); // Make sure it is big enough - if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) - { - vchSig.clear(); - return false; + bool Verify(const uint256 &hash, const std::vector& vchSig) { + // -1 = error, 0 = bad sig, 1 = good + if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + return false; + return true; + } + + bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec) { + bool fOk = false; + ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); + if (sig==NULL) + return false; + memset(p64, 0, 64); + int nBitsR = BN_num_bits(sig->r); + int nBitsS = BN_num_bits(sig->s); + if (nBitsR <= 256 && nBitsS <= 256) { + CPubKey pubkey; + GetPubKey(pubkey, true); + for (int i=0; i<4; i++) { + CECKey keyRec; + if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) { + CPubKey pubkeyRec; + keyRec.GetPubKey(pubkeyRec, true); + if (pubkeyRec == pubkey) { + rec = i; + fOk = true; + break; + } + } + } + assert(fOk); + BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]); + BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]); + } + ECDSA_SIG_free(sig); + return fOk; + } + + // reconstruct public key from a compact signature + // This is only slightly more CPU intensive than just verifying it. + // If this function succeeds, the recovered public key is guaranteed to be valid + // (the signature is a valid signature of the given data for that key) + bool Recover(const uint256 &hash, const unsigned char *p64, int rec) + { + if (rec<0 || rec>=3) + return false; + ECDSA_SIG *sig = ECDSA_SIG_new(); + BN_bin2bn(&p64[0], 32, sig->r); + BN_bin2bn(&p64[32], 32, sig->s); + bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1; + ECDSA_SIG_free(sig); + return ret; + } +}; + +}; // end of anonymous namespace + +bool CKey::Check(const unsigned char *vch) { + // Do not convert to OpenSSL's data structures for range-checking keys, + // it's easy enough to do directly. + static const unsigned char vchMax[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; + bool fIsZero = true; + for (int i=0; i<32 && fIsZero; i++) + if (vch[i] != 0) + fIsZero = false; + if (fIsZero) + return false; + for (int i=0; i<32; i++) { + if (vch[i] < vchMax[i]) + return true; + if (vch[i] > vchMax[i]) + return false; } - vchSig.resize(nSize); // Shrink to fit actual size return true; } -// create a compact signature (65 bytes), which allows reconstructing the used public key -// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. -// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, -// 0x1D = second key with even y, 0x1E = second key with odd y -bool CKey::SignCompact(uint256 hash, std::vector& vchSig) -{ - bool fOk = false; - ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); - if (sig==NULL) - return false; - vchSig.clear(); - vchSig.resize(65,0); - int nBitsR = BN_num_bits(sig->r); - int nBitsS = BN_num_bits(sig->s); - if (nBitsR <= 256 && nBitsS <= 256) - { - int nRecId = -1; - for (int i=0; i<4; i++) - { - CKey keyRec; - keyRec.fSet = true; - if (fCompressedPubKey) - keyRec.SetCompressedPubKey(); - if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) - if (keyRec.GetPubKey() == this->GetPubKey()) - { - nRecId = i; - break; - } - } - - if (nRecId == -1) - { - ECDSA_SIG_free(sig); - throw key_error("CKey::SignCompact() : unable to construct recoverable key"); - } - - vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); - BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); - BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); - fOk = true; - } - ECDSA_SIG_free(sig); - return fOk; +void CKey::MakeNewKey(bool fCompressedIn) { + do { + RAND_bytes(vch, sizeof(vch)); + } while (!Check(vch)); + fValid = true; + fCompressed = fCompressedIn; } -// reconstruct public key from a compact signature -// This is only slightly more CPU intensive than just verifying it. -// If this function succeeds, the recovered public key is guaranteed to be valid -// (the signature is a valid signature of the given data for that key) -bool CKey::SetCompactSignature(uint256 hash, const std::vector& vchSig) -{ +bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { + CECKey key; + if (!key.SetPrivKey(privkey)) + return false; + key.GetSecretBytes(vch); + fCompressed = fCompressedIn; + fValid = true; + return true; +} + +CPrivKey CKey::GetPrivKey() const { + assert(fValid); + CECKey key; + key.SetSecretBytes(vch); + CPrivKey privkey; + key.GetPrivKey(privkey); + return privkey; +} + +CPubKey CKey::GetPubKey() const { + assert(fValid); + CECKey key; + key.SetSecretBytes(vch); + CPubKey pubkey; + key.GetPubKey(pubkey, fCompressed); + return pubkey; +} + +bool CKey::Sign(const uint256 &hash, std::vector& vchSig) const { + if (!fValid) + return false; + CECKey key; + key.SetSecretBytes(vch); + return key.Sign(hash, vchSig); +} + +bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) const { + if (!fValid) + return false; + CECKey key; + key.SetSecretBytes(vch); + vchSig.resize(65); + int rec = -1; + if (!key.SignCompact(hash, &vchSig[1], rec)) + return false; + assert(rec != -1); + vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); + return true; +} + +bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { + if (!IsValid()) + return false; + CECKey key; + if (!key.SetPubKey(*this)) + return false; + if (!key.Verify(hash, vchSig)) + return false; + return true; +} + +bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector& vchSig) { if (vchSig.size() != 65) return false; - int nV = vchSig[0]; - if (nV<27 || nV>=35) + CECKey key; + if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4)) return false; - ECDSA_SIG *sig = ECDSA_SIG_new(); - BN_bin2bn(&vchSig[1],32,sig->r); - BN_bin2bn(&vchSig[33],32,sig->s); - - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (nV >= 31) - { - SetCompressedPubKey(); - nV -= 4; - } - if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) - { - fSet = true; - ECDSA_SIG_free(sig); - return true; - } - ECDSA_SIG_free(sig); - return false; -} - -bool CKey::Verify(uint256 hash, const std::vector& vchSig) -{ - // -1 = error, 0 = bad sig, 1 = good - if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) - return false; - + key.GetPubKey(*this, (vchSig[0] - 27) & 4); return true; } -bool CKey::VerifyCompact(uint256 hash, const std::vector& vchSig) -{ - CKey key; - if (!key.SetCompactSignature(hash, vchSig)) +bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector& vchSig) const { + if (!IsValid()) return false; - if (GetPubKey() != key.GetPubKey()) + if (vchSig.size() != 65) + return false; + CECKey key; + if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4)) + return false; + CPubKey pubkeyRec; + key.GetPubKey(pubkeyRec, IsCompressed()); + if (*this != pubkeyRec) return false; - return true; } -bool CKey::IsValid() -{ - if (!fSet) +bool CPubKey::IsFullyValid() const { + if (!IsValid()) return false; - - if (!EC_KEY_check_key(pkey)) + CECKey key; + if (!key.SetPubKey(*this)) return false; - - bool fCompr; - CSecret secret = GetSecret(fCompr); - CKey key2; - key2.SetSecret(secret, fCompr); - return GetPubKey() == key2.GetPubKey(); + return true; +} + +bool CPubKey::Decompress() { + if (!IsValid()) + return false; + CECKey key; + if (!key.SetPubKey(*this)) + return false; + key.GetPubKey(*this, false); + return true; } diff --git a/src/key.h b/src/key.h index 1b122112f..b9ecd4857 100644 --- a/src/key.h +++ b/src/key.h @@ -1,11 +1,10 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KEY_H #define BITCOIN_KEY_H -#include #include #include "allocators.h" @@ -13,23 +12,6 @@ #include "uint256.h" #include "hash.h" -#include // for EC_KEY definition - -// secp160k1 -// const unsigned int PRIVATE_KEY_SIZE = 192; -// const unsigned int PUBLIC_KEY_SIZE = 41; -// const unsigned int SIGNATURE_SIZE = 48; -// -// secp192k1 -// const unsigned int PRIVATE_KEY_SIZE = 222; -// const unsigned int PUBLIC_KEY_SIZE = 49; -// const unsigned int SIGNATURE_SIZE = 57; -// -// secp224k1 -// const unsigned int PRIVATE_KEY_SIZE = 250; -// const unsigned int PUBLIC_KEY_SIZE = 57; -// const unsigned int SIGNATURE_SIZE = 66; -// // secp256k1: // const unsigned int PRIVATE_KEY_SIZE = 279; // const unsigned int PUBLIC_KEY_SIZE = 65; @@ -38,12 +20,6 @@ // see www.keylength.com // script supports up to 75 for single byte push -class key_error : public std::runtime_error -{ -public: - explicit key_error(const std::string& str) : std::runtime_error(str) {} -}; - /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { @@ -63,8 +39,11 @@ public: /** An encapsulated public key. */ class CPubKey { private: + // Just store the serialized data. + // Its length can very cheaply be computed from the first byte. unsigned char vch[65]; + // Compute the length of a pubkey with a given first byte. unsigned int static GetLen(unsigned char chHeader) { if (chHeader == 2 || chHeader == 3) return 33; @@ -73,146 +52,206 @@ private: return 0; } - unsigned char *begin() { - return vch; + // Set this key data to be invalid + void Invalidate() { + vch[0] = 0xFF; } - friend class CKey; - public: - CPubKey() { vch[0] = 0xFF; } - - CPubKey(const std::vector &vchPubKeyIn) { - int len = vchPubKeyIn.empty() ? 0 : GetLen(vchPubKeyIn[0]); - if (len) { - memcpy(vch, &vchPubKeyIn[0], len); - } else { - vch[0] = 0xFF; - } + // Construct an invalid public key. + CPubKey() { + Invalidate(); } - unsigned int size() const { - return GetLen(vch[0]); + // Initialize a public key using begin/end iterators to byte data. + template + void Set(const T pbegin, const T pend) { + int len = pend == pbegin ? 0 : GetLen(pbegin[0]); + if (len && len == (pend-pbegin)) + memcpy(vch, (unsigned char*)&pbegin[0], len); + else + Invalidate(); } - const unsigned char *begin() const { - return vch; + // Construct a public key using begin/end iterators to byte data. + template + CPubKey(const T pbegin, const T pend) { + Set(pbegin, pend); } - const unsigned char *end() const { - return vch+size(); + // Construct a public key from a byte vector. + CPubKey(const std::vector &vch) { + Set(vch.begin(), vch.end()); } - friend bool operator==(const CPubKey &a, const CPubKey &b) { return memcmp(a.vch, b.vch, a.size()) == 0; } - friend bool operator!=(const CPubKey &a, const CPubKey &b) { return memcmp(a.vch, b.vch, a.size()) != 0; } + // Simply read-only vector-like interface to the pubkey data. + unsigned int size() const { return GetLen(vch[0]); } + const unsigned char *begin() const { return vch; } + const unsigned char *end() const { return vch+size(); } + const unsigned char &operator[](unsigned int pos) const { return vch[pos]; } + + // Comparator implementation. + friend bool operator==(const CPubKey &a, const CPubKey &b) { + return a.vch[0] == b.vch[0] && + memcmp(a.vch, b.vch, a.size()) == 0; + } + friend bool operator!=(const CPubKey &a, const CPubKey &b) { + return !(a == b); + } friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vch[0] < b.vch[0] || - (a.vch[0] == b.vch[0] && memcmp(a.vch+1, b.vch+1, a.size() - 1) < 0); + (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0); } + // Implement serialization, as if this was a byte vector. unsigned int GetSerializeSize(int nType, int nVersion) const { return size() + 1; } - template void Serialize(Stream &s, int nType, int nVersion) const { unsigned int len = size(); ::Serialize(s, VARINT(len), nType, nVersion); s.write((char*)vch, len); } - template void Unserialize(Stream &s, int nType, int nVersion) { unsigned int len; ::Unserialize(s, VARINT(len), nType, nVersion); if (len <= 65) { s.read((char*)vch, len); } else { - // invalid pubkey - vch[0] = 0xFF; + // invalid pubkey, skip available data char dummy; while (len--) s.read(&dummy, 1); + Invalidate(); } } + // Get the KeyID of this public key (hash of its serialization) CKeyID GetID() const { return CKeyID(Hash160(vch, vch+size())); } + // Get the 256-bit hash of this public key. uint256 GetHash() const { return Hash(vch, vch+size()); } + // just check syntactic correctness. bool IsValid() const { return size() > 0; } + // fully validate whether this is a valid public key (more expensive than IsValid()) + bool IsFullyValid() const; + + // Check whether this is a compressed public key. bool IsCompressed() const { return size() == 33; } - std::vector Raw() const { - return std::vector(vch, vch+size()); - } + // Verify a DER signature (~72 bytes). + // If this public key is not fully valid, the return value will be false. + bool Verify(const uint256 &hash, const std::vector& vchSig) const; + + // Verify a compact signature (~65 bytes). + // See CKey::SignCompact. + bool VerifyCompact(const uint256 &hash, const std::vector& vchSig) const; + + // Recover a public key from a compact signature. + bool RecoverCompact(const uint256 &hash, const std::vector& vchSig); + + // Turn this public key into an uncompressed public key. + bool Decompress(); }; // secure_allocator is defined in allocators.h // CPrivKey is a serialized private key, with all parameters included (279 bytes) typedef std::vector > CPrivKey; -// CSecret is a serialization of just the secret parameter (32 bytes) -typedef std::vector > CSecret; -/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ -class CKey -{ -protected: - EC_KEY* pkey; - bool fSet; - bool fCompressedPubKey; +/** An encapsulated private key. */ +class CKey { +private: + // Whether this private key is valid. We check for correctness when modifying the key + // data, so fValid should always correspond to the actual state. + bool fValid; + // Whether the public key corresponding to this private key is (to be) compressed. + bool fCompressed; + + // The actual byte data + unsigned char vch[32]; + + // Check whether the 32-byte array pointed to be vch is valid keydata. + bool static Check(const unsigned char *vch); public: - void SetCompressedPubKey(bool fCompressed = true); - void Reset(); + // Construct an invalid private key. + CKey() : fValid(false) { + LockObject(vch); + } - CKey(); - CKey(const CKey& b); + // Copy constructor. This is necessary because of memlocking. + CKey(const CKey &secret) : fValid(secret.fValid), fCompressed(secret.fCompressed) { + LockObject(vch); + memcpy(vch, secret.vch, sizeof(vch)); + } - CKey& operator=(const CKey& b); + // Destructor (again necessary because of memlocking). + ~CKey() { + UnlockObject(vch); + } - ~CKey(); + // Initialize using begin and end iterators to byte data. + template + void Set(const T pbegin, const T pend, bool fCompressedIn) { + if (pend - pbegin != 32) { + fValid = false; + return; + } + if (Check(&pbegin[0])) { + memcpy(vch, (unsigned char*)&pbegin[0], 32); + fValid = true; + fCompressed = fCompressedIn; + } else { + fValid = false; + } + } - bool IsNull() const; - bool IsCompressed() const; + // Simple read-only vector-like interface. + unsigned int size() const { return (fValid ? 32 : 0); } + const unsigned char *begin() const { return vch; } + const unsigned char *end() const { return vch + size(); } + // Check whether this private key is valid. + bool IsValid() const { return fValid; } + + // Check whether the public key corresponding to this private key is (to be) compressed. + bool IsCompressed() const { return fCompressed; } + + // Initialize from a CPrivKey (serialized OpenSSL private key data). + bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed); + + // Generate a new private key using a cryptographic PRNG. void MakeNewKey(bool fCompressed); - bool SetPrivKey(const CPrivKey& vchPrivKey); - bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); - CSecret GetSecret(bool &fCompressed) const; + + // Convert the private key to a CPrivKey (serialized OpenSSL private key data). + // This is expensive. CPrivKey GetPrivKey() const; - bool SetPubKey(const CPubKey& vchPubKey); + + // Compute the public key from a private key. + // This is expensive. CPubKey GetPubKey() const; - bool Sign(uint256 hash, std::vector& vchSig); + // Create a DER-serialized signature. + bool Sign(const uint256 &hash, std::vector& vchSig) const; - // create a compact signature (65 bytes), which allows reconstructing the used public key + // Create a compact signature (65 bytes), which allows reconstructing the used public key. // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, - // 0x1D = second key with even y, 0x1E = second key with odd y - bool SignCompact(uint256 hash, std::vector& vchSig); - - // reconstruct public key from a compact signature - // This is only slightly more CPU intensive than just verifying it. - // If this function succeeds, the recovered public key is guaranteed to be valid - // (the signature is a valid signature of the given data for that key) - bool SetCompactSignature(uint256 hash, const std::vector& vchSig); - - bool Verify(uint256 hash, const std::vector& vchSig); - - // Verify a compact signature - bool VerifyCompact(uint256 hash, const std::vector& vchSig); - - bool IsValid(); + // 0x1D = second key with even y, 0x1E = second key with odd y, + // add 0x04 for compressed keys. + bool SignCompact(const uint256 &hash, std::vector& vchSig) const; }; #endif diff --git a/src/keystore.cpp b/src/keystore.cpp index e0cf805a1..808f8c24e 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -15,61 +15,50 @@ bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const return true; } -bool CBasicKeyStore::AddKey(const CKey& key) +bool CKeyStore::AddKey(const CKey &key) { + return AddKeyPubKey(key, key.GetPubKey()); +} + +bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) { - bool fCompressed = false; - CSecret secret = key.GetSecret(fCompressed); - { - LOCK(cs_KeyStore); - mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed); - } + LOCK(cs_KeyStore); + mapKeys[pubkey.GetID()] = key; return true; } bool CBasicKeyStore::AddCScript(const CScript& redeemScript) { - { - LOCK(cs_KeyStore); - mapScripts[redeemScript.GetID()] = redeemScript; - } + LOCK(cs_KeyStore); + mapScripts[redeemScript.GetID()] = redeemScript; return true; } bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const { - bool result; - { - LOCK(cs_KeyStore); - result = (mapScripts.count(hash) > 0); - } - return result; + LOCK(cs_KeyStore); + return mapScripts.count(hash) > 0; } - bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const { + LOCK(cs_KeyStore); + ScriptMap::const_iterator mi = mapScripts.find(hash); + if (mi != mapScripts.end()) { - LOCK(cs_KeyStore); - ScriptMap::const_iterator mi = mapScripts.find(hash); - if (mi != mapScripts.end()) - { - redeemScriptOut = (*mi).second; - return true; - } + redeemScriptOut = (*mi).second; + return true; } return false; } bool CCryptoKeyStore::SetCrypted() { - { - LOCK(cs_KeyStore); - if (fUseCrypto) - return true; - if (!mapKeys.empty()) - return false; - fUseCrypto = true; - } + LOCK(cs_KeyStore); + if (fUseCrypto) + return true; + if (!mapKeys.empty()) + return false; + fUseCrypto = true; return true; } @@ -99,14 +88,13 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) { const CPubKey &vchPubKey = (*mi).second.first; const std::vector &vchCryptedSecret = (*mi).second.second; - CSecret vchSecret; + CKeyingMaterial vchSecret; if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) return false; if (vchSecret.size() != 32) return false; CKey key; - key.SetPubKey(vchPubKey); - key.SetSecret(vchSecret); + key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); if (key.GetPubKey() == vchPubKey) break; return false; @@ -117,23 +105,22 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) return true; } -bool CCryptoKeyStore::AddKey(const CKey& key) +bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) { { LOCK(cs_KeyStore); if (!IsCrypted()) - return CBasicKeyStore::AddKey(key); + return CBasicKeyStore::AddKeyPubKey(key, pubkey); if (IsLocked()) return false; std::vector vchCryptedSecret; - CPubKey vchPubKey = key.GetPubKey(); - bool fCompressed; - if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret)) + CKeyingMaterial vchSecret(key.begin(), key.end()); + if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) return false; - if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) + if (!AddCryptedKey(pubkey, vchCryptedSecret)) return false; } return true; @@ -164,13 +151,12 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const { const CPubKey &vchPubKey = (*mi).second.first; const std::vector &vchCryptedSecret = (*mi).second.second; - CSecret vchSecret; + CKeyingMaterial vchSecret; if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) return false; if (vchSecret.size() != 32) return false; - keyOut.SetPubKey(vchPubKey); - keyOut.SetSecret(vchSecret); + keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); return true; } } @@ -204,13 +190,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) fUseCrypto = true; BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys) { - CKey key; - if (!key.SetSecret(mKey.second.first, mKey.second.second)) - return false; - const CPubKey vchPubKey = key.GetPubKey(); + const CKey &key = mKey.second; + CPubKey vchPubKey = key.GetPubKey(); + CKeyingMaterial vchSecret(key.begin(), key.end()); std::vector vchCryptedSecret; - bool fCompressed; - if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret)) + if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) return false; if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; diff --git a/src/keystore.h b/src/keystore.h index ab369bbf4..49a7bf569 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -21,7 +21,8 @@ public: virtual ~CKeyStore() {} // Add a key to the store. - virtual bool AddKey(const CKey& key) =0; + virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0; + virtual bool AddKey(const CKey &key); // Check whether a key corresponding to a given address is present in the store. virtual bool HaveKey(const CKeyID &address) const =0; @@ -33,18 +34,9 @@ public: virtual bool AddCScript(const CScript& redeemScript) =0; virtual bool HaveCScript(const CScriptID &hash) const =0; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0; - - virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const - { - CKey key; - if (!GetKey(address, key)) - return false; - vchSecret = key.GetSecret(fCompressed); - return true; - } }; -typedef std::map > KeyMap; +typedef std::map KeyMap; typedef std::map ScriptMap; /** Basic key store, that keeps keys in an address->secret map */ @@ -55,7 +47,7 @@ protected: ScriptMap mapScripts; public: - bool AddKey(const CKey& key); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); bool HaveKey(const CKeyID &address) const { bool result; @@ -85,8 +77,7 @@ public: KeyMap::const_iterator mi = mapKeys.find(address); if (mi != mapKeys.end()) { - keyOut.Reset(); - keyOut.SetSecret((*mi).second.first, (*mi).second.second); + keyOut = mi->second; return true; } } @@ -146,7 +137,7 @@ public: bool Lock(); virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - bool AddKey(const CKey& key); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); bool HaveKey(const CKeyID &address) const { { diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 7c43e5839..9118770f4 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -218,8 +218,8 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() ss << strMessageMagic; ss << ui->messageIn_VM->document()->toPlainText().toStdString(); - CKey key; - if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) + CPubKey pubkey; + if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig)) { ui->signatureIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); @@ -227,7 +227,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr)) + if (!(CBitcoinAddress(pubkey.GetID()) == addr)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("") + tr("Message verification failed.") + QString("")); diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 77cef0273..d46309eaa 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -54,20 +54,18 @@ Value importprivkey(const Array& params, bool fHelp) if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - CKey key; - bool fCompressed; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); - CKeyID vchAddress = key.GetPubKey().GetID(); + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + CKeyID vchAddress = pubkey.GetID(); { LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->MarkDirty(); pwalletMain->SetAddressBookName(vchAddress, strLabel); - if (!pwalletMain->AddKey(key)) + if (!pwalletMain->AddKeyPubKey(key, pubkey)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); - + if (fRescan) { pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); pwalletMain->ReacceptWalletTransactions(); @@ -91,9 +89,8 @@ Value dumpprivkey(const Array& params, bool fHelp) CKeyID keyID; if (!address.GetKeyID(keyID)) throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); - CSecret vchSecret; - bool fCompressed; - if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed)) + CKey vchSecret; + if (!pwalletMain->GetKey(keyID, vchSecret)) throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); - return CBitcoinSecret(vchSecret, fCompressed).ToString(); + return CBitcoinSecret(vchSecret).ToString(); } diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index fb9811b92..c1e05466e 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -407,10 +407,7 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fGood = vchSecret.SetString(k.get_str()); if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - CKey key; - bool fCompressed; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); + CKey key = vchSecret.GetKey(); tempKeystore.AddKey(key); } } diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 64ee39081..89f094fa8 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -374,11 +374,11 @@ Value verifymessage(const Array& params, bool fHelp) ss << strMessageMagic; ss << strMessage; - CKey key; - if (!key.SetCompactSignature(ss.GetHash(), vchSig)) + CPubKey pubkey; + if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) return false; - return (key.GetPubKey().GetID() == keyID); + return (pubkey.GetID() == keyID); } @@ -719,7 +719,7 @@ static CScript _createmultisig(const Array& params) throw runtime_error( strprintf("not enough keys supplied " "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); - std::vector pubkeys; + std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) { @@ -737,16 +737,18 @@ static CScript _createmultisig(const Array& params) if (!pwalletMain->GetPubKey(keyID, vchPubKey)) throw runtime_error( strprintf("no full public key for address %s",ks.c_str())); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsFullyValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } // Case 2: hex public key else if (IsHex(ks)) { CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsFullyValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } else { diff --git a/src/script.cpp b/src/script.cpp index 7e1d5785e..2c7fd5987 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1100,11 +1100,7 @@ bool CheckSig(vector vchSig, vector vchPubKey, CSc if (signatureCache.Get(sighash, vchSig, vchPubKey)) return true; - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; - - if (!key.Verify(sighash, vchSig)) + if (!CPubKey(vchPubKey).Verify(sighash, vchSig)) return false; if (!(flags & SCRIPT_VERIFY_NOCACHE)) @@ -1770,13 +1766,13 @@ void CScript::SetDestination(const CTxDestination& dest) boost::apply_visitor(CScriptVisitor(this), dest); } -void CScript::SetMultisig(int nRequired, const std::vector& keys) +void CScript::SetMultisig(int nRequired, const std::vector& keys) { this->clear(); *this << EncodeOP_N(nRequired); - BOOST_FOREACH(const CKey& key, keys) - *this << key.GetPubKey(); + BOOST_FOREACH(const CPubKey& key, keys) + *this << key; *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; } @@ -1801,20 +1797,17 @@ bool CScriptCompressor::IsToScriptID(CScriptID &hash) const return false; } -bool CScriptCompressor::IsToPubKey(std::vector &pubkey) const +bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const { if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && (script[1] == 0x02 || script[1] == 0x03)) { - pubkey.resize(33); - memcpy(&pubkey[0], &script[1], 33); + pubkey.Set(&script[1], &script[34]); return true; } if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG && script[1] == 0x04) { - pubkey.resize(65); - memcpy(&pubkey[0], &script[1], 65); - CKey key; - return (key.SetPubKey(CPubKey(pubkey))); // SetPubKey fails if this is not a valid public key, a case that would not be compressible + pubkey.Set(&script[1], &script[66]); + return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible } return false; } @@ -1835,7 +1828,7 @@ bool CScriptCompressor::Compress(std::vector &out) const memcpy(&out[1], &scriptID, 20); return true; } - std::vector pubkey; + CPubKey pubkey; if (IsToPubKey(pubkey)) { out.resize(33); memcpy(&out[1], &pubkey[1], 32); @@ -1888,14 +1881,12 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector vch(33, 0x00); + unsigned char vch[33] = {}; vch[0] = nSize - 2; memcpy(&vch[1], &in[0], 32); - CKey key; - if (!key.SetPubKey(CPubKey(vch))) + CPubKey pubkey(&vch[0], &vch[33]); + if (!pubkey.Decompress()) return false; - key.SetCompressedPubKey(false); // Decompress public key - const CPubKey pubkey = key.GetPubKey(); assert(pubkey.size() == 65); script.resize(67); script[0] = 65; diff --git a/src/script.h b/src/script.h index e63900354..3cbb2cf32 100644 --- a/src/script.h +++ b/src/script.h @@ -550,7 +550,7 @@ public: void SetDestination(const CTxDestination& address); - void SetMultisig(int nRequired, const std::vector& keys); + void SetMultisig(int nRequired, const std::vector& keys); void PrintHex() const @@ -621,7 +621,7 @@ protected: // form). bool IsToKeyID(CKeyID &hash) const; bool IsToScriptID(CScriptID &hash) const; - bool IsToPubKey(std::vector &pubkey) const; + bool IsToPubKey(CPubKey &pubkey) const; bool Compress(std::vector &out) const; unsigned int GetSpecialSize(unsigned int nSize) const; diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 7602fa93a..2741672a8 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -133,9 +133,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); - bool fCompressedOut = false; - CSecret privkey = secret.GetSecret(fCompressedOut); - BOOST_CHECK_MESSAGE(fCompressedOut == isCompressed, "compressed mismatch:" + strTest); + CKey privkey = secret.GetKey(); + BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); // Private key must be invalid public key @@ -187,8 +186,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) if(isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + CKey key; + key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); + assert(key.IsValid()); CBitcoinSecret secret; - secret.SetSecret(CSecret(exp_payload.begin(), exp_payload.end()), isCompressed); + secret.SetKey(key); BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest); } else diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 4a2851cf4..0d349a990 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -73,14 +73,13 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key) CBitcoinSecret vchSecret; BOOST_CHECK(vchSecret.SetString(strSecret)); - CKey key; - bool fCompressed; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + vector vchPubKey(pubkey.begin(), pubkey.end()); CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); - filter.insert(key.GetPubKey().Raw()); - uint160 hash = key.GetPubKey().GetID(); + filter.insert(vchPubKey); + uint160 hash = pubkey.GetID(); filter.insert(vector(hash.begin(), hash.end())); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 0a6df88fe..c004521d1 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -26,8 +26,8 @@ static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); #ifdef KEY_TESTS_DUMPINFO void dumpKeyInfo(uint256 privkey) { - CSecret secret; - secret.resize(32); + CKey key; + key.resize(32); memcpy(&secret[0], &privkey, 32); vector sec; sec.resize(32); @@ -62,29 +62,24 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK( bsecret2C.SetString(strSecret2C)); BOOST_CHECK(!baddress1.SetString(strAddressBad)); - bool fCompressed; - CSecret secret1 = bsecret1.GetSecret (fCompressed); - BOOST_CHECK(fCompressed == false); - CSecret secret2 = bsecret2.GetSecret (fCompressed); - BOOST_CHECK(fCompressed == false); - CSecret secret1C = bsecret1C.GetSecret(fCompressed); - BOOST_CHECK(fCompressed == true); - CSecret secret2C = bsecret2C.GetSecret(fCompressed); - BOOST_CHECK(fCompressed == true); + CKey key1 = bsecret1.GetKey(); + BOOST_CHECK(key1.IsCompressed() == false); + CKey key2 = bsecret2.GetKey(); + BOOST_CHECK(key2.IsCompressed() == false); + CKey key1C = bsecret1C.GetKey(); + BOOST_CHECK(key1C.IsCompressed() == true); + CKey key2C = bsecret2C.GetKey(); + BOOST_CHECK(key1C.IsCompressed() == true); - BOOST_CHECK(secret1 == secret1C); - BOOST_CHECK(secret2 == secret2C); + CPubKey pubkey1 = key1. GetPubKey(); + CPubKey pubkey2 = key2. GetPubKey(); + CPubKey pubkey1C = key1C.GetPubKey(); + CPubKey pubkey2C = key2C.GetPubKey(); - CKey key1, key2, key1C, key2C; - key1.SetSecret(secret1, false); - key2.SetSecret(secret2, false); - key1C.SetSecret(secret1, true); - key2C.SetSecret(secret2, true); - - BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID())); - BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID())); - BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID())); - BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID())); + BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID())); + BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID())); + BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID())); + BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID())); for (int n=0; n<16; n++) { @@ -100,25 +95,25 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key1C.Sign(hashMsg, sign1C)); BOOST_CHECK(key2C.Sign(hashMsg, sign2C)); - BOOST_CHECK( key1.Verify(hashMsg, sign1)); - BOOST_CHECK(!key1.Verify(hashMsg, sign2)); - BOOST_CHECK( key1.Verify(hashMsg, sign1C)); - BOOST_CHECK(!key1.Verify(hashMsg, sign2C)); + BOOST_CHECK( pubkey1.Verify(hashMsg, sign1)); + BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2)); + BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C)); - BOOST_CHECK(!key2.Verify(hashMsg, sign1)); - BOOST_CHECK( key2.Verify(hashMsg, sign2)); - BOOST_CHECK(!key2.Verify(hashMsg, sign1C)); - BOOST_CHECK( key2.Verify(hashMsg, sign2C)); + BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1)); + BOOST_CHECK( pubkey2.Verify(hashMsg, sign2)); + BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C)); + BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C)); - BOOST_CHECK( key1C.Verify(hashMsg, sign1)); - BOOST_CHECK(!key1C.Verify(hashMsg, sign2)); - BOOST_CHECK( key1C.Verify(hashMsg, sign1C)); - BOOST_CHECK(!key1C.Verify(hashMsg, sign2C)); + BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1)); + BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2)); + BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C)); - BOOST_CHECK(!key2C.Verify(hashMsg, sign1)); - BOOST_CHECK( key2C.Verify(hashMsg, sign2)); - BOOST_CHECK(!key2C.Verify(hashMsg, sign1C)); - BOOST_CHECK( key2C.Verify(hashMsg, sign2C)); + BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1)); + BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2)); + BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C)); + BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C)); // compact signatures (with key recovery) @@ -129,18 +124,17 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); - CKey rkey1, rkey2, rkey1C, rkey2C; + CPubKey rkey1, rkey2, rkey1C, rkey2C; - BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1)); - BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2)); - BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C)); - BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C)); + BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1)); + BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2)); + BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C)); + BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C)); - - BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey()); - BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey()); - BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey()); - BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey()); + BOOST_CHECK(rkey1 == pubkey1); + BOOST_CHECK(rkey2 == pubkey2); + BOOST_CHECK(rkey1C == pubkey1C); + BOOST_CHECK(rkey2C == pubkey2C); } } diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index d6f836d36..9ef932b5b 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -30,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, CScript result; result << OP_0; // CHECKMULTISIG bug workaround - BOOST_FOREACH(CKey key, keys) + BOOST_FOREACH(const CKey &key, keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index ee0d25a2f..65f0ad0cd 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -145,19 +145,19 @@ BOOST_AUTO_TEST_CASE(set) // Test the CScript::Set* methods CBasicKeyStore keystore; CKey key[4]; - std::vector keys; + std::vector keys; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keys.push_back(key[i]); + keys.push_back(key[i].GetPubKey()); } CScript inner[4]; inner[0].SetDestination(key[0].GetPubKey().GetID()); - inner[1].SetMultisig(2, std::vector(keys.begin(), keys.begin()+2)); - inner[2].SetMultisig(1, std::vector(keys.begin(), keys.begin()+2)); - inner[3].SetMultisig(2, std::vector(keys.begin(), keys.begin()+3)); + inner[1].SetMultisig(2, std::vector(keys.begin(), keys.begin()+2)); + inner[2].SetMultisig(1, std::vector(keys.begin(), keys.begin()+2)); + inner[3].SetMultisig(2, std::vector(keys.begin(), keys.begin()+3)); CScript outer[4]; for (int i = 0; i < 4; i++) @@ -248,12 +248,12 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CCoinsViewCache coins(coinsDummy); CBasicKeyStore keystore; CKey key[3]; - vector keys; + vector keys; for (int i = 0; i < 3; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keys.push_back(key[i]); + keys.push_back(key[i].GetPubKey()); } CTransaction txFrom; diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 5d5a1525f..e7ad52627 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -211,7 +211,7 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac // and vice-versa) // result << OP_0; - BOOST_FOREACH(CKey key, keys) + BOOST_FOREACH(const CKey &key, keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); @@ -221,7 +221,7 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac return result; } CScript -sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction) +sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) { std::vector keys; keys.push_back(key); @@ -333,11 +333,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) // Test the CombineSignatures function CBasicKeyStore keystore; vector keys; + vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; key.MakeNewKey(i%2 == 1); keys.push_back(key); + pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } @@ -390,7 +392,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(combined == scriptSig); // Hardest case: Multisig 2-of-3 - scriptPubKey.SetMultisig(2, keys); + scriptPubKey.SetMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, txFrom, txTo, 0); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 1762680ad..5a87f1760 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -37,12 +37,12 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) scriptSig << OP_0 << Serialize(s1); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); - std::vector keys; + std::vector keys; for (int i = 0; i < 3; i++) { CKey k; k.MakeNewKey(true); - keys.push_back(k); + keys.push_back(k.GetPubKey()); } CScript s2; s2.SetMultisig(1, keys); diff --git a/src/wallet.cpp b/src/wallet.cpp index c70ea20e8..5efc45583 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -32,26 +32,28 @@ CPubKey CWallet::GenerateNewKey() bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets RandAddSeedPerfmon(); - CKey key; - key.MakeNewKey(fCompressed); + CKey secret; + secret.MakeNewKey(fCompressed); // Compressed public keys were introduced in version 0.6.0 if (fCompressed) SetMinVersion(FEATURE_COMPRPUBKEY); - if (!AddKey(key)) + CPubKey pubkey = secret.GetPubKey(); + if (!AddKeyPubKey(secret, pubkey)) throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); - return key.GetPubKey(); + return pubkey; } -bool CWallet::AddKey(const CKey& key) +bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) { - if (!CCryptoKeyStore::AddKey(key)) + if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) return false; if (!fFileBacked) return true; - if (!IsCrypted()) - return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); + if (!IsCrypted()) { + return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey()); + } return true; } diff --git a/src/wallet.h b/src/wallet.h index dcba4675e..7fcb8e13c 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -136,9 +136,9 @@ public: // Generate a new key CPubKey GenerateNewKey(); // Adds a key to the store, and saves it to disk. - bool AddKey(const CKey& key); + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); // Adds a key to the store, without saving it to disk (used by LoadWallet) - bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } + bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 81a21443a..4a73413d2 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -262,52 +262,33 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "key" || strType == "wkey") { - vector vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; - CKey key; - if (strType == "key") + if (!vchPubKey.IsValid()) { - CPrivKey pkey; - ssValue >> pkey; - key.SetPubKey(vchPubKey); - if (!key.SetPrivKey(pkey)) - { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; - } - if (key.GetPubKey() != vchPubKey) - { - strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; - return false; - } - if (!key.IsValid()) - { - strErr = "Error reading wallet database: invalid CPrivKey"; - return false; - } + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; } - else - { + CKey key; + CPrivKey pkey; + if (strType == "key") + ssValue >> pkey; + else { CWalletKey wkey; ssValue >> wkey; - key.SetPubKey(vchPubKey); - if (!key.SetPrivKey(wkey.vchPrivKey)) - { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; - } - if (key.GetPubKey() != vchPubKey) - { - strErr = "Error reading wallet database: CWalletKey pubkey inconsistency"; - return false; - } - if (!key.IsValid()) - { - strErr = "Error reading wallet database: invalid CWalletKey"; - return false; - } + pkey = wkey.vchPrivKey; } - if (!pwallet->LoadKey(key)) + if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed())) + { + strErr = "Error reading wallet database: CPrivKey corrupt"; + return false; + } + if (key.GetPubKey() != vchPubKey) + { + strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; + return false; + } + if (!pwallet->LoadKey(key, vchPubKey)) { strErr = "Error reading wallet database: LoadKey failed"; return false; diff --git a/src/walletdb.h b/src/walletdb.h index a3e779ab9..8ae6c3ff4 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -53,18 +53,18 @@ public: bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false); + return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); } bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret, bool fEraseUnencryptedKey = true) { nWalletDBUpdated++; - if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false)) + if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) return false; if (fEraseUnencryptedKey) { - Erase(std::make_pair(std::string("key"), vchPubKey.Raw())); - Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw())); + Erase(std::make_pair(std::string("key"), vchPubKey)); + Erase(std::make_pair(std::string("wkey"), vchPubKey)); } return true; } @@ -101,7 +101,7 @@ public: bool WriteDefaultKey(const CPubKey& vchPubKey) { nWalletDBUpdated++; - return Write(std::string("defaultkey"), vchPubKey.Raw()); + return Write(std::string("defaultkey"), vchPubKey); } bool ReadPool(int64 nPool, CKeyPool& keypool) From 896185d7ed3fa23415424c608f0897d6139640f4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 4 May 2013 16:10:09 +0200 Subject: [PATCH 63/69] Make signature cache store CPubKeys --- src/allocators.h | 4 ++++ src/key.h | 7 +++---- src/script.cpp | 20 ++++++++++++-------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/allocators.h b/src/allocators.h index b4490ce27..85af8fe37 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -176,6 +176,10 @@ private: {} }; +// +// Functions for directly locking/unlocking memory objects. +// Intended for non-dynamically allocated structures. +// template void LockObject(const T &t) { LockedPageManager::instance.LockRange((void*)(&t), sizeof(T)); } diff --git a/src/key.h b/src/key.h index b9ecd4857..ce469ad29 100644 --- a/src/key.h +++ b/src/key.h @@ -84,7 +84,7 @@ public: Set(vch.begin(), vch.end()); } - // Simply read-only vector-like interface to the pubkey data. + // Simple read-only vector-like interface to the pubkey data. unsigned int size() const { return GetLen(vch[0]); } const unsigned char *begin() const { return vch; } const unsigned char *end() const { return vch+size(); } @@ -109,12 +109,11 @@ public: } template void Serialize(Stream &s, int nType, int nVersion) const { unsigned int len = size(); - ::Serialize(s, VARINT(len), nType, nVersion); + ::WriteCompactSize(s, len); s.write((char*)vch, len); } template void Unserialize(Stream &s, int nType, int nVersion) { - unsigned int len; - ::Unserialize(s, VARINT(len), nType, nVersion); + unsigned int len = ::ReadCompactSize(s); if (len <= 65) { s.read((char*)vch, len); } else { diff --git a/src/script.cpp b/src/script.cpp index 2c7fd5987..b41166635 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -16,7 +16,7 @@ using namespace boost; #include "sync.h" #include "util.h" -bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); +bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); @@ -1033,13 +1033,13 @@ class CSignatureCache { private: // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple, std::vector > sigdata_type; + typedef boost::tuple, CPubKey> sigdata_type; std::set< sigdata_type> setValid; boost::shared_mutex cs_sigcache; public: bool - Get(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { boost::shared_lock lock(cs_sigcache); @@ -1050,7 +1050,7 @@ public: return false; } - void Set(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + void Set(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { // DoS prevention: limit cache size to less than 10MB // (~200 bytes per cache entry times 50,000 entries) @@ -1081,11 +1081,15 @@ public: } }; -bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, +bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) { static CSignatureCache signatureCache; + CPubKey pubkey(vchPubKey); + if (!pubkey.IsValid()) + return false; + // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) return false; @@ -1097,14 +1101,14 @@ bool CheckSig(vector vchSig, vector vchPubKey, CSc uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (signatureCache.Get(sighash, vchSig, vchPubKey)) + if (signatureCache.Get(sighash, vchSig, pubkey)) return true; - if (!CPubKey(vchPubKey).Verify(sighash, vchSig)) + if (!pubkey.Verify(sighash, vchSig)) return false; if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, vchPubKey); + signatureCache.Set(sighash, vchSig, pubkey); return true; } From bb70bbfc5d561af230c2efcf08e660e2add1b0f1 Mon Sep 17 00:00:00 2001 From: Michagogo Date: Sat, 25 May 2013 23:29:28 +0300 Subject: [PATCH 64/69] Made more generic by removing specific version references Tweaked a little bit to provide examples. Squashed commits into 1, while hoping not to break anything --- doc/release-process.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/release-process.md b/doc/release-process.md index 17d6a089c..dc2101e1c 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -17,11 +17,11 @@ Release Process ###tag version in git - git tag -a v0.8.0 + git tag -a v(new version, e.g. 0.8.0) ###write release notes. git shortlog helps a lot, for example: - git shortlog --no-merges v0.7.2..v0.8.0 + git shortlog --no-merges v(current version, e.g. 0.7.2)..v(new version, e.g. 0.8.0) * * * @@ -30,7 +30,7 @@ Release Process From a directory containing the bitcoin source, gitian-builder and gitian.sigs export SIGNER=(your gitian key, ie bluematt, sipa, etc) - export VERSION=0.8.0 + export VERSION=(new version, e.g. 0.8.0) cd ./gitian-builder Fetch and build inputs: (first time, or when dependency versions change) @@ -134,7 +134,7 @@ Commit your signature to gitian.sigs: From a directory containing bitcoin source, gitian.sigs and gitian zips - export VERSION=0.5.1 + export VERSION=(new version, e.g. 0.8.0) mkdir bitcoin-${VERSION}-linux-gitian pushd bitcoin-${VERSION}-linux-gitian unzip ../bitcoin-${VERSION}-linux-gitian.zip @@ -161,4 +161,4 @@ From a directory containing bitcoin source, gitian.sigs and gitian zips popd - Upload gitian zips to SourceForge -- Celebrate \ No newline at end of file +- Celebrate From d98bf10f23e0e633ff2ff33075a353d30bf862b4 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 30 May 2013 15:51:41 +0200 Subject: [PATCH 65/69] Move pMiningKey init out of StartRPCThreads This commit decouples the pMiningKey initialization and shutdown from the RPC threads. `getwork` and `getblocktemplate` rely on pMiningKey, and can also be ran from the debug window in the UI even when the RPC server is not running. Solves issue #2706. --- src/bitcoinrpc.cpp | 9 --------- src/bitcoinrpc.h | 4 +++- src/init.cpp | 3 +++ src/rpcmining.cpp | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 2c4744a57..a9b73fd5a 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -30,10 +30,6 @@ using namespace boost; using namespace boost::asio; using namespace json_spirit; -// Key used by getwork/getblocktemplate miners. -// Allocated in StartRPCThreads, free'd in StopRPCThreads -CReserveKey* pMiningKey = NULL; - static std::string strRPCUserColonPass; // These are created by StartRPCThreads, destroyed in StopRPCThreads @@ -726,9 +722,6 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptorstop(); diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index cf5b13798..547cccf44 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -123,7 +123,9 @@ public: }; extern const CRPCTable tableRPC; -extern CReserveKey* pMiningKey; + +extern void InitRPCMining(); +extern void ShutdownRPCMining(); extern int64 nWalletUnlockTime; extern int64 AmountFromValue(const json_spirit::Value& value); diff --git a/src/init.cpp b/src/init.cpp index 767d7525a..9c807b288 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -96,6 +96,7 @@ void Shutdown() RenameThread("bitcoin-shutoff"); nTransactionsUpdated++; StopRPCThreads(); + ShutdownRPCMining(); bitdb.Flush(false); StopNode(); { @@ -1081,6 +1082,8 @@ bool AppInit2(boost::thread_group& threadGroup) StartNode(threadGroup); + // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly. + InitRPCMining(); if (fServer) StartRPCThreads(); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index b8b745963..845e7f1f9 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -11,6 +11,21 @@ using namespace json_spirit; using namespace std; +// Key used by getwork/getblocktemplate miners. +// Allocated in InitRPCMining, free'd in ShutdownRPCMining +static CReserveKey* pMiningKey = NULL; + +void InitRPCMining() +{ + // getwork/getblocktemplate mining rewards paid here: + pMiningKey = new CReserveKey(pwalletMain); +} + +void ShutdownRPCMining() +{ + delete pMiningKey; pMiningKey = NULL; +} + Value getgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) From 1df6a90a0662e39ea1d67724f248f569b83fdd65 Mon Sep 17 00:00:00 2001 From: Timon Rapp Date: Fri, 31 May 2013 15:39:28 +0200 Subject: [PATCH 66/69] Added NSHighResolutionCapable flag to Info.plist for better font rendering on Retina displays. --- share/qt/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/share/qt/Info.plist b/share/qt/Info.plist index 2312094c4..6f64c3164 100644 --- a/share/qt/Info.plist +++ b/share/qt/Info.plist @@ -31,5 +31,7 @@ + NSHighResolutionCapable + From 25c0cce7fb494fcb871d134e28b26504d30e34d3 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 31 May 2013 14:02:24 +0200 Subject: [PATCH 67/69] Qt5 compatibility This commit squashes all the changes in the Qt5 branch relative to master. Backward compatibility with Qt4 is retained. Original authors: - Philip Kaufmann - Jonas Schnelli --- bitcoin-qt.pro | 6 +++++- doc/readme-qt.rst | 6 ++++++ src/qt/addressbookpage.cpp | 5 +++++ src/qt/bitcoin.cpp | 4 ++++ src/qt/bitcoingui.cpp | 2 ++ src/qt/guiutil.cpp | 20 +++++++++++++++++++- src/qt/macdockiconhandler.mm | 30 ++++++++++++++++++++++-------- src/qt/paymentserver.cpp | 2 ++ src/qt/qrcodedialog.cpp | 2 ++ src/qt/rpcconsole.cpp | 2 ++ src/qt/sendcoinsdialog.cpp | 4 ++++ src/qt/splashscreen.cpp | 1 + src/qt/transactionview.cpp | 4 ++++ src/qt/walletframe.cpp | 4 +--- src/qt/walletframe.h | 3 ++- src/qt/walletstack.h | 1 + src/qt/walletview.cpp | 8 ++++++++ 17 files changed, 90 insertions(+), 14 deletions(-) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index f33f44fd6..336b85cae 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -3,7 +3,8 @@ TARGET = bitcoin-qt macx:TARGET = "Bitcoin-Qt" VERSION = 0.8.2 INCLUDEPATH += src src/json src/qt -QT += network +QT += core gui network +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE CONFIG += no_include_pwd CONFIG += thread @@ -211,6 +212,7 @@ HEADERS += src/qt/bitcoingui.h \ src/leveldb.h \ src/threadsafety.h \ src/limitedmap.h \ + src/qt/macnotificationhandler.h \ src/qt/splashscreen.h SOURCES += src/qt/bitcoin.cpp \ @@ -312,6 +314,7 @@ DEFINES += BITCOIN_QT_TEST macx: CONFIG -= app_bundle } +# Todo: Remove this line when switching to Qt5, as that option was removed CODECFORTR = UTF-8 # for lrelease/lupdate @@ -335,6 +338,7 @@ QMAKE_EXTRA_COMPILERS += TSQM OTHER_FILES += README.md \ doc/*.rst \ doc/*.txt \ + doc/*.md \ src/qt/res/bitcoin-qt.rc \ src/test/*.cpp \ src/test/*.h \ diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst index 1bc3d701a..95cb33650 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -28,6 +28,12 @@ for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ libssl-dev libdb++-dev libminiupnpc-dev +For Qt 5 you need the following, otherwise you get an error with lrelease when running qmake: + +:: + + apt-get install qt5-qmake libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev-tools + then execute the following: :: diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 8529c88b3..8906174d7 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -143,8 +143,13 @@ void AddressBookPage::setModel(AddressTableModel *model) ui->tableView->sortByColumn(0, Qt::AscendingOrder); // Set column widths +#if QT_VERSION < 0x050000 ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); +#else + ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch); + ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); +#endif connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged())); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f525d1bb3..354c5af45 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -17,7 +17,9 @@ #include "splashscreen.h" #include +#if QT_VERSION < 0x050000 #include +#endif #include #include #include @@ -118,9 +120,11 @@ int main(int argc, char *argv[]) // Command-line options take precedence: ParseParameters(argc, argv); +#if QT_VERSION < 0x050000 // Internal string conversion is all UTF-8 QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); +#endif Q_INIT_RESOURCE(bitcoin); QApplication app(argc, argv); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 78a69af8b..a4589860b 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -44,7 +44,9 @@ #include #include #include +#if QT_VERSION < 0x050000 #include +#endif #include #include #include diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 2105f0730..6937febfe 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -13,8 +13,12 @@ #include #include #include +#if QT_VERSION >= 0x050000 +#include +#else #include -#include // For Qt::escape +#endif +#include // for Qt::mightBeRichText #include #include #include @@ -86,7 +90,13 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) SendCoinsRecipient rv; rv.address = uri.path(); rv.amount = 0; + +#if QT_VERSION < 0x050000 QList > items = uri.queryItems(); +#else + QUrlQuery uriQuery(uri); + QList > items = uriQuery.queryItems(); +#endif for (QList >::iterator i = items.begin(); i != items.end(); i++) { bool fShouldReturnFalse = false; @@ -139,7 +149,11 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out) QString HtmlEscape(const QString& str, bool fMultiLine) { +#if QT_VERSION < 0x050000 QString escaped = Qt::escape(str); +#else + QString escaped = str.toHtmlEscaped(); +#endif if(fMultiLine) { escaped = escaped.replace("\n", "
\n"); @@ -176,7 +190,11 @@ QString getSaveFileName(QWidget *parent, const QString &caption, QString myDir; if(dir.isEmpty()) // Default to user documents location { +#if QT_VERSION < 0x050000 myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); +#else + myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); +#endif } else { diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index b6ea8e1d0..53b49c42e 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -2,8 +2,8 @@ #include #include - -extern void qt_mac_set_dock_menu(QMenu*); +#include +#include #undef slots #include @@ -47,11 +47,11 @@ extern void qt_mac_set_dock_menu(QMenu*); MacDockIconHandler::MacDockIconHandler() : QObject() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; + this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; this->m_dummyWidget = new QWidget(); this->m_dockMenu = new QMenu(this->m_dummyWidget); - qt_mac_set_dock_menu(this->m_dockMenu); + [pool release]; } @@ -74,15 +74,29 @@ QMenu *MacDockIconHandler::dockMenu() void MacDockIconHandler::setIcon(const QIcon &icon) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSImage *image; + NSImage *image = nil; if (icon.isNull()) image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; else { + // generate NSImage from QIcon and use this as dock icon. QSize size = icon.actualSize(QSize(128, 128)); QPixmap pixmap = icon.pixmap(size); - CGImageRef cgImage = pixmap.toMacCGImageRef(); - image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; - CFRelease(cgImage); + + // write temp file hack (could also be done through QIODevice [memory]) + QTemporaryFile notificationIconFile; + if (!pixmap.isNull() && notificationIconFile.open()) { + QImageWriter writer(¬ificationIconFile, "PNG"); + if (writer.write(pixmap.toImage())) { + const char *cString = notificationIconFile.fileName().toUtf8().data(); + NSString *macString = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding]; + image = [[NSImage alloc] initWithContentsOfFile:macString]; + } + } + + if(!image) { + // if testnet image could not be created, load std. app icon + image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; + } } [NSApp setApplicationIconImage:image]; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index a92e6fc32..0b0bce55b 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -18,7 +18,9 @@ #include #include #include +#if QT_VERSION < 0x050000 #include +#endif using namespace boost; diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp index ca9497512..6ddcaaf5d 100644 --- a/src/qt/qrcodedialog.cpp +++ b/src/qt/qrcodedialog.cpp @@ -7,7 +7,9 @@ #include "optionsmodel.h" #include +#if QT_VERSION < 0x050000 #include +#endif #include diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 50f22b877..7f90f4a55 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -8,7 +8,9 @@ #include #include #include +#if QT_VERSION < 0x050000 #include +#endif #include #include diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index eb3ce48a6..2c7bab204 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -93,7 +93,11 @@ void SendCoinsDialog::on_sendButton_clicked() QStringList formatted; foreach(const SendCoinsRecipient &rcp, recipients) { +#if QT_VERSION < 0x050000 formatted.append(tr("%1 to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address)); +#else + formatted.append(tr("%1 to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), rcp.label.toHtmlEscaped(), rcp.address)); +#endif } fNewRecipientAllowed = false; diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index f8d16699c..95948a6cb 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -3,6 +3,7 @@ #include "util.h" #include +#undef loop /* ugh, remove this when the #define loop is gone from util.h */ #include SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) : diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 9240b71c7..a43e29c47 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -176,7 +176,11 @@ void TransactionView::setModel(WalletModel *model) transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23); transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120); transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120); +#if QT_VERSION < 0x050000 transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch); +#else + transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch); +#endif transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100); } } diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 83e4255c9..50c03ac62 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -8,11 +8,9 @@ #include "bitcoingui.h" #include "walletstack.h" -#include +#include #include -#include - WalletFrame::WalletFrame(BitcoinGUI *_gui) : QFrame(_gui), gui(_gui), diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 3649185e8..d7092f987 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -17,8 +17,9 @@ class WalletStack; class WalletFrame : public QFrame { Q_OBJECT + public: - explicit WalletFrame(BitcoinGUI *_gui); + explicit WalletFrame(BitcoinGUI *_gui = 0); ~WalletFrame(); void setClientModel(ClientModel *clientModel); diff --git a/src/qt/walletstack.h b/src/qt/walletstack.h index ea4cc121d..506d595c0 100644 --- a/src/qt/walletstack.h +++ b/src/qt/walletstack.h @@ -40,6 +40,7 @@ QT_END_NAMESPACE class WalletStack : public QStackedWidget { Q_OBJECT + public: explicit WalletStack(QWidget *parent = 0); ~WalletStack(); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 6d44c174b..277c05669 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -21,7 +21,11 @@ #include #include #include +#if QT_VERSION < 0x050000 #include +#else +#include +#endif #include #include @@ -232,7 +236,11 @@ void WalletView::encryptWallet(bool status) void WalletView::backupWallet() { +#if QT_VERSION < 0x050000 QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); +#else + QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); +#endif QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); if (!filename.isEmpty()) { if (!walletModel->backupWallet(filename)) { From 3260b4c09006ea5c1b00c599a14e6c706ac760f8 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sun, 28 Apr 2013 17:37:50 +0200 Subject: [PATCH 68/69] remove GetBoolArg() fDefault parameter defaulting to false - explicitly set the default of all GetBoolArg() calls - rework getarg_test.cpp and util_tests.cpp to cover this change - some indentation fixes - move macdockiconhandler.h include in bitcoin.cpp to the "our headers" section --- src/bitcoinrpc.cpp | 6 +++--- src/init.cpp | 28 ++++++++++++++-------------- src/main.cpp | 4 ++-- src/qt/bitcoin.cpp | 16 ++++++++-------- src/qt/splashscreen.cpp | 2 +- src/rpcmining.cpp | 22 +++++++++++----------- src/test/getarg_tests.cpp | 26 ++++++-------------------- src/test/util_tests.cpp | 24 ++++++++++++------------ src/util.cpp | 7 +++---- src/util.h | 2 +- 10 files changed, 61 insertions(+), 76 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index a1d76e181..c99b74f18 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -757,7 +757,7 @@ void StartRPCThreads() rpc_io_service = new asio::io_service(); rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23); - const bool fUseSSL = GetBoolArg("-rpcssl"); + const bool fUseSSL = GetBoolArg("-rpcssl", false); if (fUseSSL) { @@ -1037,7 +1037,7 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s // Observe safe mode string strWarning = GetWarnings("rpc"); - if (strWarning != "" && !GetBoolArg("-disablesafemode") && + if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && !pcmd->okSafeMode) throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); @@ -1071,7 +1071,7 @@ Object CallRPC(const string& strMethod, const Array& params) GetConfigFile().string().c_str())); // Connect to localhost - bool fUseSSL = GetBoolArg("-rpcssl"); + bool fUseSSL = GetBoolArg("-rpcssl", false); asio::io_service io_service; ssl::context context(io_service, ssl::context::sslv23); context.set_options(ssl::context::no_sslv2); diff --git a/src/init.cpp b/src/init.cpp index 226e93e9a..78f838f7c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -198,7 +198,7 @@ bool AppInit(int argc, char* argv[]) exit(ret); } #if !defined(WIN32) - fDaemon = GetBoolArg("-daemon"); + fDaemon = GetBoolArg("-daemon", false); if (fDaemon) { // Daemonize @@ -495,7 +495,7 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 2: parameter interactions - fTestNet = GetBoolArg("-testnet"); + fTestNet = GetBoolArg("-testnet", false); Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); if (mapArgs.count("-bind")) { @@ -526,7 +526,7 @@ bool AppInit2(boost::thread_group& threadGroup) SoftSetBoolArg("-discover", false); } - if (GetBoolArg("-salvagewallet")) { + if (GetBoolArg("-salvagewallet", false)) { // Rewrite just private keys: rescan to find transactions SoftSetBoolArg("-rescan", true); } @@ -543,8 +543,8 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 3: parameter-to-internal-flags - fDebug = GetBoolArg("-debug"); - fBenchmark = GetBoolArg("-benchmark"); + fDebug = GetBoolArg("-debug", false); + fBenchmark = GetBoolArg("-benchmark", false); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", 0); @@ -559,20 +559,20 @@ bool AppInit2(boost::thread_group& threadGroup) if (fDebug) fDebugNet = true; else - fDebugNet = GetBoolArg("-debugnet"); + fDebugNet = GetBoolArg("-debugnet", false); if (fDaemon) fServer = true; else - fServer = GetBoolArg("-server"); + fServer = GetBoolArg("-server", false); /* force fServer when running without GUI */ #if !defined(QT_GUI) fServer = true; #endif - fPrintToConsole = GetBoolArg("-printtoconsole"); - fPrintToDebugger = GetBoolArg("-printtodebugger"); - fLogTimestamps = GetBoolArg("-logtimestamps"); + fPrintToConsole = GetBoolArg("-printtoconsole", false); + fPrintToDebugger = GetBoolArg("-printtodebugger", false); + fLogTimestamps = GetBoolArg("-logtimestamps", false); if (mapArgs.count("-timeout")) { @@ -677,7 +677,7 @@ bool AppInit2(boost::thread_group& threadGroup) } } - if (GetBoolArg("-salvagewallet")) + if (GetBoolArg("-salvagewallet", false)) { // Recover readable keypairs: if (!CWalletDB::Recover(bitdb, "wallet.dat", true)) @@ -799,7 +799,7 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 7: load block chain - fReindex = GetBoolArg("-reindex"); + fReindex = GetBoolArg("-reindex", false); // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/ filesystem::path blocksDir = GetDataDir() / "blocks"; @@ -922,7 +922,7 @@ bool AppInit2(boost::thread_group& threadGroup) } printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); - if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) + if (GetBoolArg("-printblockindex", false) || GetBoolArg("-printblocktree", false)) { PrintBlockTree(); return false; @@ -1018,7 +1018,7 @@ bool AppInit2(boost::thread_group& threadGroup) RegisterWallet(pwalletMain); CBlockIndex *pindexRescan = pindexBest; - if (GetBoolArg("-rescan")) + if (GetBoolArg("-rescan", false)) pindexRescan = pindexGenesisBlock; else { diff --git a/src/main.cpp b/src/main.cpp index 24e1c2334..a98b83b6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2931,7 +2931,7 @@ string GetWarnings(string strFor) string strStatusBar; string strRPC; - if (GetBoolArg("-testsafemode")) + if (GetBoolArg("-testsafemode", false)) strRPC = "test"; if (!CLIENT_VERSION_IS_RELEASE) @@ -4175,7 +4175,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) // Priority order to process transactions list vOrphan; // list memory doesn't move map > mapDependers; - bool fPrintPriority = GetBoolArg("-printpriority"); + bool fPrintPriority = GetBoolArg("-printpriority", false); // This vector will be sorted into a priority queue: vector vecPriority; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f525d1bb3..fbf57fffd 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -15,6 +15,9 @@ #include "ui_interface.h" #include "paymentserver.h" #include "splashscreen.h" +#ifdef Q_OS_MAC +#include "macdockiconhandler.h" +#endif #include #include @@ -23,10 +26,6 @@ #include #include -#ifdef Q_OS_MAC -#include "macdockiconhandler.h" -#endif - #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) #define _BITCOIN_QT_PLUGINS_INCLUDED #define __INSURE__ @@ -152,7 +151,7 @@ int main(int argc, char *argv[]) // as it is used to locate QSettings) QApplication::setOrganizationName("Bitcoin"); QApplication::setOrganizationDomain("bitcoin.org"); - if(GetBoolArg("-testnet")) // Separate UI settings for testnet + if (GetBoolArg("-testnet", false)) // Separate UI settings for testnet QApplication::setApplicationName("Bitcoin-Qt-testnet"); else QApplication::setApplicationName("Bitcoin-Qt"); @@ -204,13 +203,14 @@ int main(int argc, char *argv[]) #ifdef Q_OS_MAC // on mac, also change the icon now because it would look strange to have a testnet splash (green) and a std app icon (orange) - if(GetBoolArg("-testnet")) { + if(GetBoolArg("-testnet", false)) + { MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); } #endif SplashScreen splash(QPixmap(), 0); - if (GetBoolArg("-splash", true) && !GetBoolArg("-min")) + if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) { splash.show(); splash.setAutoFillBackground(true); @@ -254,7 +254,7 @@ int main(int argc, char *argv[]) window.setCurrentWallet("~Default"); // If -min option passed, start window minimized. - if(GetBoolArg("-min")) + if(GetBoolArg("-min", false)) { window.showMinimized(); } diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index f8d16699c..d60b2ef4b 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -26,7 +26,7 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) : // load the bitmap for writing some text over it QPixmap newPixmap; - if(GetBoolArg("-testnet")) { + if(GetBoolArg("-testnet", false)) { newPixmap = QPixmap(":/images/splash_testnet"); } else { diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 845e7f1f9..d2cac6870 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -33,7 +33,7 @@ Value getgenerate(const Array& params, bool fHelp) "getgenerate\n" "Returns true or false."); - return GetBoolArg("-gen"); + return GetBoolArg("-gen", false); } @@ -84,16 +84,16 @@ Value getmininginfo(const Array& params, bool fHelp) "Returns an object containing mining-related information."); Object obj; - obj.push_back(Pair("blocks", (int)nBestHeight)); - obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); - obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx)); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("generate", GetBoolArg("-gen"))); - obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); - obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", fTestNet)); + obj.push_back(Pair("blocks", (int)nBestHeight)); + obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); + obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + obj.push_back(Pair("generate", GetBoolArg("-gen", false))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); + obj.push_back(Pair("hashespersec", gethashespersec(params, false))); + obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); + obj.push_back(Pair("testnet", fTestNet)); return obj; } diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 78953d296..c89d218f8 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -6,8 +6,7 @@ BOOST_AUTO_TEST_SUITE(getarg_tests) -static void -ResetArgs(const std::string& strArg) +static void ResetArgs(const std::string& strArg) { std::vector vecArg; boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); @@ -26,62 +25,50 @@ ResetArgs(const std::string& strArg) BOOST_AUTO_TEST_CASE(boolarg) { ResetArgs("-foo"); - BOOST_CHECK(GetBoolArg("-foo")); BOOST_CHECK(GetBoolArg("-foo", false)); BOOST_CHECK(GetBoolArg("-foo", true)); - BOOST_CHECK(!GetBoolArg("-fo")); BOOST_CHECK(!GetBoolArg("-fo", false)); BOOST_CHECK(GetBoolArg("-fo", true)); - BOOST_CHECK(!GetBoolArg("-fooo")); BOOST_CHECK(!GetBoolArg("-fooo", false)); BOOST_CHECK(GetBoolArg("-fooo", true)); ResetArgs("-foo=0"); - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", false)); BOOST_CHECK(!GetBoolArg("-foo", true)); ResetArgs("-foo=1"); - BOOST_CHECK(GetBoolArg("-foo")); BOOST_CHECK(GetBoolArg("-foo", false)); BOOST_CHECK(GetBoolArg("-foo", true)); // New 0.6 feature: auto-map -nosomething to !-something: ResetArgs("-nofoo"); - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", false)); BOOST_CHECK(!GetBoolArg("-foo", true)); ResetArgs("-nofoo=1"); - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", false)); BOOST_CHECK(!GetBoolArg("-foo", true)); ResetArgs("-foo -nofoo"); // -foo should win - BOOST_CHECK(GetBoolArg("-foo")); BOOST_CHECK(GetBoolArg("-foo", false)); BOOST_CHECK(GetBoolArg("-foo", true)); ResetArgs("-foo=1 -nofoo=1"); // -foo should win - BOOST_CHECK(GetBoolArg("-foo")); BOOST_CHECK(GetBoolArg("-foo", false)); BOOST_CHECK(GetBoolArg("-foo", true)); ResetArgs("-foo=0 -nofoo=0"); // -foo should win - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", false)); BOOST_CHECK(!GetBoolArg("-foo", true)); // New 0.6 feature: treat -- same as -: ResetArgs("--foo=1"); - BOOST_CHECK(GetBoolArg("-foo")); BOOST_CHECK(GetBoolArg("-foo", false)); BOOST_CHECK(GetBoolArg("-foo", true)); ResetArgs("--nofoo=1"); - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", false)); BOOST_CHECK(!GetBoolArg("-foo", true)); @@ -133,7 +120,7 @@ BOOST_AUTO_TEST_CASE(intarg) BOOST_AUTO_TEST_CASE(doubledash) { ResetArgs("--foo"); - BOOST_CHECK_EQUAL(GetBoolArg("-foo"), true); + BOOST_CHECK_EQUAL(GetBoolArg("-foo", false), true); ResetArgs("--foo=verbose --bar=1"); BOOST_CHECK_EQUAL(GetArg("-foo", ""), "verbose"); @@ -143,25 +130,24 @@ BOOST_AUTO_TEST_CASE(doubledash) BOOST_AUTO_TEST_CASE(boolargno) { ResetArgs("-nofoo"); - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", true)); BOOST_CHECK(!GetBoolArg("-foo", false)); ResetArgs("-nofoo=1"); - BOOST_CHECK(!GetBoolArg("-foo")); BOOST_CHECK(!GetBoolArg("-foo", true)); BOOST_CHECK(!GetBoolArg("-foo", false)); ResetArgs("-nofoo=0"); - BOOST_CHECK(GetBoolArg("-foo")); BOOST_CHECK(GetBoolArg("-foo", true)); BOOST_CHECK(GetBoolArg("-foo", false)); ResetArgs("-foo --nofoo"); - BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", true)); + BOOST_CHECK(GetBoolArg("-foo", false)); ResetArgs("-nofoo -foo"); // foo always wins: - BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", true)); + BOOST_CHECK(GetBoolArg("-foo", false)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 1b0ccad51..64bd3a1b2 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE(util_criticalsection) } BOOST_AUTO_TEST_CASE(util_MedianFilter) -{ +{ CMedianFilter filter(5, 15); BOOST_CHECK_EQUAL(filter.median(), 15); @@ -56,10 +56,10 @@ BOOST_AUTO_TEST_CASE(util_MedianFilter) } static const unsigned char ParseHex_expected[65] = { - 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, - 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, - 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, - 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, + 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, + 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, + 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, + 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f }; BOOST_AUTO_TEST_CASE(util_ParseHex) @@ -123,13 +123,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters) BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty()); ParseParameters(5, (char**)argv_test); - // expectation: -ignored is ignored (program name argument), + // expectation: -ignored is ignored (program name argument), // -a, -b and -ccc end up in map, -d ignored because it is after // a non-option argument (non-GNU option parsing) BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3); - BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc") + BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc") && !mapArgs.count("f") && !mapArgs.count("-d")); - BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc") + BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc") && !mapMultiArgs.count("f") && !mapMultiArgs.count("-d")); BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple"); @@ -154,10 +154,10 @@ BOOST_AUTO_TEST_CASE(util_GetArg) BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345); BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL); BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1); - BOOST_CHECK_EQUAL(GetBoolArg("booltest1"), true); - BOOST_CHECK_EQUAL(GetBoolArg("booltest2"), false); - BOOST_CHECK_EQUAL(GetBoolArg("booltest3"), false); - BOOST_CHECK_EQUAL(GetBoolArg("booltest4"), true); + BOOST_CHECK_EQUAL(GetBoolArg("booltest1", false), true); + BOOST_CHECK_EQUAL(GetBoolArg("booltest2", false), false); + BOOST_CHECK_EQUAL(GetBoolArg("booltest3", false), false); + BOOST_CHECK_EQUAL(GetBoolArg("booltest4", false), true); } BOOST_AUTO_TEST_CASE(util_WildcardMatch) diff --git a/src/util.cpp b/src/util.cpp index 4c9b897f5..0bd296023 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -518,7 +518,7 @@ static void InterpretNegativeSetting(string name, map& mapSettin positive.append(name.begin()+3, name.end()); if (mapSettingsRet.count(positive) == 0) { - bool value = !GetBoolArg(name); + bool value = !GetBoolArg(name, false); mapSettingsRet[positive] = (value ? "1" : "0"); } } @@ -1171,7 +1171,6 @@ bool TruncateFile(FILE *file, unsigned int length) { #endif } - // this function tries to raise the file descriptor limit to the requested number. // It returns the actual file descriptor limit (which may be more or less than nMinFD) int RaiseFileDescriptorLimit(int nMinFD) { @@ -1257,8 +1256,8 @@ void ShrinkDebugFile() fclose(file); } } - else if(file != NULL) - fclose(file); + else if (file != NULL) + fclose(file); } diff --git a/src/util.h b/src/util.h index d9ad74f6c..941e0d99a 100644 --- a/src/util.h +++ b/src/util.h @@ -390,7 +390,7 @@ int64 GetArg(const std::string& strArg, int64 nDefault); * @param default (true or false) * @return command-line argument or default value */ -bool GetBoolArg(const std::string& strArg, bool fDefault=false); +bool GetBoolArg(const std::string& strArg, bool fDefault); /** * Set an argument if it doesn't already have a value From 80fccb0eb3756af5385460d9008b9b8b17b7cda5 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sun, 19 May 2013 20:20:06 +0200 Subject: [PATCH 69/69] Bitcoin-Qt: setup testnet GUI directly - this directly sets up all GUI elements that have testnet special-casing without first setting up main net stuff and changing afterwards (titles, icons etc.) - also fixes 2 wrong icons shown during testnet usage on our toolbar --- src/qt/bitcoin.cpp | 13 +------- src/qt/bitcoingui.cpp | 76 ++++++++++++++++++++++++------------------- src/qt/bitcoingui.h | 6 ++-- 3 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index b858e1c17..9bcac5979 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -15,9 +15,6 @@ #include "ui_interface.h" #include "paymentserver.h" #include "splashscreen.h" -#ifdef Q_OS_MAC -#include "macdockiconhandler.h" -#endif #include #if QT_VERSION < 0x050000 @@ -205,14 +202,6 @@ int main(int argc, char *argv[]) return 1; } -#ifdef Q_OS_MAC - // on mac, also change the icon now because it would look strange to have a testnet splash (green) and a std app icon (orange) - if(GetBoolArg("-testnet", false)) - { - MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); - } -#endif - SplashScreen splash(QPixmap(), 0); if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) { @@ -232,7 +221,7 @@ int main(int argc, char *argv[]) boost::thread_group threadGroup; - BitcoinGUI window; + BitcoinGUI window(GetBoolArg("-testnet", false), 0); guiref = &window; QTimer* pollShutdownTimer = new QTimer(guiref); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a4589860b..190da6caf 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -57,7 +57,7 @@ const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; -BitcoinGUI::BitcoinGUI(QWidget *parent) : +BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : QMainWindow(parent), clientModel(0), encryptWalletAction(0), @@ -69,14 +69,30 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) : prevBlocks(0) { restoreWindowGeometry(); - setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet")); + #ifndef Q_OS_MAC - QApplication::setWindowIcon(QIcon(":icons/bitcoin")); - setWindowIcon(QIcon(":icons/bitcoin")); + if (!fIsTestnet) + { + setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet")); + QApplication::setWindowIcon(QIcon(":icons/bitcoin")); + setWindowIcon(QIcon(":icons/bitcoin")); + } + else + { + setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet") + " " + tr("[testnet]")); + QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet")); + setWindowIcon(QIcon(":icons/bitcoin_testnet")); + } #else setUnifiedTitleAndToolBarOnMac(true); QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); + + if (!fIsTestnet) + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin")); + else + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); #endif + // Create wallet frame and make it the central widget walletFrame = new WalletFrame(this); setCentralWidget(walletFrame); @@ -86,7 +102,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) : // Create actions for the toolbar, menu bar and tray/dock icon // Needs walletFrame to be initialized - createActions(); + createActions(fIsTestnet); // Create application menu bar createMenuBar(); @@ -95,7 +111,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) : createToolBars(); // Create system tray icon and notification - createTrayIcon(); + createTrayIcon(fIsTestnet); // Create status bar statusBar(); @@ -159,7 +175,7 @@ BitcoinGUI::~BitcoinGUI() #endif } -void BitcoinGUI::createActions() +void BitcoinGUI::createActions(bool fIsTestnet) { QActionGroup *tabGroup = new QActionGroup(this); @@ -213,7 +229,10 @@ void BitcoinGUI::createActions() quitAction->setStatusTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); quitAction->setMenuRole(QAction::QuitRole); - aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin"), this); + if (!fIsTestnet) + aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin"), this); + else + aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin"), this); aboutAction->setStatusTip(tr("Show information about Bitcoin")); aboutAction->setMenuRole(QAction::AboutRole); aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); @@ -222,7 +241,10 @@ void BitcoinGUI::createActions() optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin")); optionsAction->setMenuRole(QAction::PreferencesRole); - toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this); + if (!fIsTestnet) + toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this); + else + toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this); toggleHideAction->setStatusTip(tr("Show or hide the main Window")); encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); @@ -299,27 +321,6 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) this->clientModel = clientModel; if(clientModel) { - // Replace some strings and icons, when using the testnet - if(clientModel->isTestNet()) - { - setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]")); -#ifndef Q_OS_MAC - QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet")); - setWindowIcon(QIcon(":icons/bitcoin_testnet")); -#else - MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); -#endif - if(trayIcon) - { - // Just attach " [testnet]" to the existing tooltip - trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]")); - trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); - } - - toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); - aboutAction->setIcon(QIcon(":/icons/toolbar_testnet")); - } - // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions, // while the client has not yet fully loaded createTrayIconMenu(); @@ -354,13 +355,22 @@ void BitcoinGUI::removeAllWallets() walletFrame->removeAllWallets(); } -void BitcoinGUI::createTrayIcon() +void BitcoinGUI::createTrayIcon(bool fIsTestnet) { #ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); - trayIcon->setToolTip(tr("Bitcoin client")); - trayIcon->setIcon(QIcon(":/icons/toolbar")); + if (!fIsTestnet) + { + trayIcon->setToolTip(tr("Bitcoin client")); + trayIcon->setIcon(QIcon(":/icons/toolbar")); + } + else + { + trayIcon->setToolTip(tr("Bitcoin client") + " " + tr("[testnet]")); + trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); + } + trayIcon->show(); #endif diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index f361a62a4..685ce8b43 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -43,7 +43,7 @@ class BitcoinGUI : public QMainWindow public: static const QString DEFAULT_WALLET; - explicit BitcoinGUI(QWidget *parent = 0); + explicit BitcoinGUI(bool fIsTestnet = false, QWidget *parent = 0); ~BitcoinGUI(); /** Set the client model. @@ -113,13 +113,13 @@ private: int prevBlocks; /** Create the main UI actions. */ - void createActions(); + void createActions(bool fIsTestnet); /** Create the menu bar and sub-menus. */ void createMenuBar(); /** Create the toolbars */ void createToolBars(); /** Create system tray icon and notification */ - void createTrayIcon(); + void createTrayIcon(bool fIsTestnet); /** Create system tray menu (or setup the dock menu) */ void createTrayIconMenu(); /** Save window size and position */