├── .gitignore ├── HEADER ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── buildViaTravis.sh ├── javadoc_cleanup.gradle ├── push_javadoc.sh ├── stylesheet.css └── wrapper │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lombok.config ├── settings.gradle └── src └── main └── java └── org └── tron ├── common └── storage │ └── leveldb │ └── LevelDbDataSourceImpl.java ├── core ├── db │ ├── RevokingDatabase.java │ └── common │ │ ├── BatchSourceInter.java │ │ ├── DbSourceInter.java │ │ ├── SourceInter.java │ │ └── iterator │ │ ├── DBIterator.java │ │ └── StoreIterator.java ├── db2 │ ├── common │ │ ├── DB.java │ │ ├── Flusher.java │ │ ├── HashDB.java │ │ ├── IRevokingDB.java │ │ ├── Instance.java │ │ ├── Key.java │ │ ├── LevelDB.java │ │ ├── TxCacheDB.java │ │ ├── Value.java │ │ └── WrappedByteArray.java │ └── core │ │ ├── AbstractSnapshot.java │ │ ├── Chainbase.java │ │ ├── ISession.java │ │ ├── Snapshot.java │ │ ├── SnapshotImpl.java │ │ ├── SnapshotManager.java │ │ └── SnapshotRoot.java └── exception │ ├── ItemNotFoundException.java │ ├── RevokingStoreIllegalStateException.java │ └── StoreException.java └── utils ├── ByteUtil.java └── FileUtil.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # IDEA 26 | .idea 27 | *iml 28 | .DS_Store 29 | 30 | # gradle 31 | .gradle 32 | build 33 | 34 | # log 35 | logs 36 | consensus-logs 37 | 38 | # lombok 39 | out 40 | 41 | # Eclipse IDE specific files and folders 42 | /.project 43 | /.classpath 44 | /.settings/ 45 | /.apt_generated/ 46 | 47 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-present, RxJava Contributors. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in 4 | compliance with the License. You may obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See 10 | the License for the specific language governing permissions and limitations under the License. 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://jitpack.io/v/tronprotocol/chainbase.svg)](https://jitpack.io/#tronprotocol/chainbase) 2 | 3 | # chainbase 4 | A decentralized database for blockchain. 5 | 6 | ## Dependencies 7 | 8 | The lastest version is **1.0.0**. 9 | 10 | ### GRADLE 11 | 12 | Step 1. Add the JitPack repository in your root build.gradle at the end of repositories: 13 | ``` 14 | allprojects { 15 | repositories { 16 | ... 17 | maven { url 'https://jitpack.io' } 18 | } 19 | } 20 | ``` 21 | Step 2. Add the dependency. 22 | ``` 23 | dependencies { 24 | implementation 'com.github.tronprotocol:chainbase:${version}' 25 | } 26 | ``` 27 | 28 | ### MAVEN 29 | 30 | Step 1. Add the JitPack repository to your build file. 31 | 32 | ``` 33 | 34 | 35 | jitpack.io 36 | https://jitpack.io 37 | 38 | 39 | 40 | ``` 41 | Step 2. Add the dependency. 42 | ``` 43 | 44 | com.github.tronprotocol 45 | chainbase 46 | ${version} 47 | 48 | 49 | ``` 50 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | mavenCentral() 5 | maven { 6 | url "https://plugins.gradle.org/m2/" 7 | } 8 | } 9 | } 10 | 11 | group = "com.github.tronprotocol" 12 | ext.githubProjectName = "chainbase" 13 | 14 | version = project.properties["release.version"] 15 | 16 | description = "chainbase – a decentralized database for blockchain." 17 | 18 | apply plugin: "java-library" 19 | //apply plugin: "checkstyle" 20 | apply plugin: "jacoco" 21 | apply plugin: "maven" 22 | apply plugin: "maven-publish" 23 | //apply plugin: "me.champeau.gradle.jmh" 24 | 25 | sourceCompatibility = JavaVersion.VERSION_1_8 26 | targetCompatibility = JavaVersion.VERSION_1_8 27 | 28 | // Dependency versions 29 | // --------------------------------------- 30 | 31 | def junitVersion = "4.12" 32 | def mockitoVersion = "2.1.0" 33 | def jmhLibVersion = "1.20" 34 | def testNgVersion = "6.11" 35 | def guavaVersion = "24.1-jre" 36 | def jacocoVersion = "0.8.0" 37 | def leveldbVersion = "1.8" 38 | def logbackVersion = "1.2.3" 39 | def jansiVersion = "1.16" 40 | def lombokVersion = "1.18.2" 41 | def slf4jVersion = "1.7.25" 42 | // -------------------------------------- 43 | 44 | repositories { 45 | mavenCentral() 46 | } 47 | 48 | dependencies { 49 | testImplementation "junit:junit:$junitVersion" 50 | testImplementation "org.mockito:mockito-core:$mockitoVersion" 51 | 52 | testImplementation "org.testng:testng:$testNgVersion" 53 | 54 | compile "com.google.guava:guava:$guavaVersion" 55 | compile "org.fusesource.leveldbjni:leveldbjni-all:$leveldbVersion" 56 | compile "org.fusesource.jansi:jansi:$jansiVersion" 57 | compile "org.slf4j:slf4j-api:$slf4jVersion" 58 | compile "org.slf4j:jcl-over-slf4j:$slf4jVersion" 59 | compile "ch.qos.logback:logback-classic:$logbackVersion" 60 | compile "org.projectlombok:lombok:$lombokVersion" 61 | } 62 | 63 | //javadoc { 64 | // failOnError = false 65 | // exclude "**/test/**" 66 | // options { 67 | // windowTitle = "Chainbase Javadoc ${project.version}" 68 | // } 69 | // // Clear the following options to make the docs consistent with the old format 70 | // options.addStringOption("top").value = "" 71 | // options.addStringOption("doctitle").value = "" 72 | // options.addStringOption("header").value = "" 73 | // options.stylesheetFile = new File(projectDir, "gradle/stylesheet.css"); 74 | // 75 | // options.links( 76 | // "https://docs.oracle.com/javase/7/docs/api/" 77 | // ) 78 | // 79 | // if (JavaVersion.current().isJava7()) { 80 | // // "./gradle/stylesheet.css" only supports Java 7 81 | // options.addStringOption("stylesheetfile", rootProject.file("./gradle/stylesheet.css").toString()) 82 | // } 83 | //} 84 | 85 | task sourcesJar(type: Jar, dependsOn: classes) { 86 | classifier = "sources" 87 | from sourceSets.main.allSource 88 | } 89 | 90 | //task javadocJar(type: Jar, dependsOn: javadoc) { 91 | // classifier = "javadoc" 92 | // from javadoc.destinationDir 93 | //} 94 | 95 | artifacts { 96 | archives jar 97 | archives sourcesJar 98 | // archives javadocJar 99 | } 100 | 101 | 102 | //jmh { 103 | // jmhVersion = jmhLibVersion 104 | // humanOutputFile = null 105 | // includeTests = false 106 | // jvmArgs = ["-Djmh.ignoreLock=true"] 107 | // jvmArgsAppend = ["-Djmh.separateClasspathJAR=true"] 108 | // 109 | // if (project.hasProperty("jmh")) { 110 | // include = ".*" + project.jmh + ".*" 111 | // println("JMH: " + include); 112 | // } 113 | // 114 | //} 115 | 116 | //plugins.withType(EclipsePlugin) { 117 | // project.eclipse.classpath.plusConfigurations += [ configurations.jmh ] 118 | //} 119 | 120 | test { 121 | 122 | testLogging { 123 | // showing skipped occasionally should prevent CI timeout due to lack of standard output 124 | events=["skipped", "failed"] // "started", "passed" 125 | // showStandardStreams = true 126 | exceptionFormat="full" 127 | 128 | debug.events = ["skipped", "failed"] 129 | debug.exceptionFormat="full" 130 | 131 | info.events = ["failed", "skipped"] 132 | info.exceptionFormat="full" 133 | 134 | warn.events = ["failed", "skipped"] 135 | warn.exceptionFormat="full" 136 | } 137 | 138 | maxHeapSize = "1200m" 139 | 140 | if (System.getenv("CI") == null) { 141 | maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 142 | } 143 | } 144 | 145 | task testng(type: Test) { 146 | useTestNG() 147 | testLogging { 148 | events=["skipped", "failed"] 149 | exceptionFormat="full" 150 | 151 | debug.events = ["skipped", "failed"] 152 | debug.exceptionFormat="full" 153 | 154 | info.events = ["failed", "skipped"] 155 | info.exceptionFormat="full" 156 | 157 | warn.events = ["failed", "skipped"] 158 | warn.exceptionFormat="full" 159 | } 160 | } 161 | 162 | check.dependsOn testng 163 | 164 | jacoco { 165 | toolVersion = jacocoVersion // See http://www.eclemma.org/jacoco/. 166 | } 167 | 168 | jacocoTestReport { 169 | reports { 170 | xml.enabled = true 171 | html.enabled = true 172 | } 173 | 174 | afterEvaluate { 175 | classDirectories = files(classDirectories.files.collect { 176 | fileTree(dir: it, 177 | exclude: ["io/reactivex/tck/**"]) 178 | }) 179 | } 180 | } 181 | 182 | build.dependsOn jacocoTestReport 183 | 184 | //checkstyle { 185 | // configFile file("checkstyle.xml") 186 | // ignoreFailures = true 187 | // toolVersion ="6.19" 188 | //} 189 | 190 | //apply from: file("gradle/javadoc_cleanup.gradle") 191 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | release.scope=patch 2 | release.version=1.0.0-SNAPSHOT 3 | -------------------------------------------------------------------------------- /gradle/buildViaTravis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script will build the project. 3 | 4 | buildTag="$TRAVIS_TAG" 5 | 6 | if [ "$buildTag" != "" ] && [ "${buildTag:0:3}" != "v2." ]; then 7 | echo -e "Wrong tag on the 2.x brach: $buildTag : build stopped" 8 | exit 1 9 | fi 10 | 11 | export GRADLE_OPTS=-Xmx1024m 12 | 13 | if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then 14 | echo -e "Build Pull Request #$TRAVIS_PULL_REQUEST => Branch [$TRAVIS_BRANCH]" 15 | ./gradlew -PreleaseMode=pr build 16 | elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ]; then 17 | echo -e 'Build Branch with Snapshot => Branch ['$TRAVIS_BRANCH']' 18 | ./gradlew -PreleaseMode=branch -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" build --stacktrace 19 | elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" != "" ]; then 20 | echo -e 'Build Branch for Release => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG']' 21 | ./gradlew -PreleaseMode=full -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" build --stacktrace 22 | else 23 | echo -e 'WARN: Should not be here => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG'] Pull Request ['$TRAVIS_PULL_REQUEST']' 24 | fi 25 | -------------------------------------------------------------------------------- /gradle/javadoc_cleanup.gradle: -------------------------------------------------------------------------------- 1 | // remove the excessive whitespaces between method arguments in the javadocs 2 | task javadocCleanup(dependsOn: "javadoc") doLast { 3 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/Flowable.html')); 4 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/Observable.html')); 5 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/Single.html')); 6 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/Maybe.html')); 7 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/Completable.html')); 8 | 9 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/flowables/ConnectableFlowable.html')); 10 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/observables/ConnectableObservable.html')); 11 | 12 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/subjects/ReplaySubject.html')); 13 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/processors/ReplayProcessor.html')); 14 | fixJavadocFile(rootProject.file('build/docs/javadoc/io/reactivex/plugins/RxJavaPlugins.html')); 15 | } 16 | 17 | def fixJavadocFile(file) { 18 | println("Cleaning up: " + file); 19 | String fileContents = file.getText('UTF-8') 20 | 21 | // lots of spaces after the previous method argument 22 | fileContents = fileContents.replaceAll(",\\s{4,}", ",\n "); 23 | 24 | // lots of spaces after the @NonNull annotations 25 | fileContents = fileContents.replaceAll("@NonNull\\s{4,}", "@NonNull "); 26 | 27 | // lots of spaces after the @Nullable annotations 28 | fileContents = fileContents.replaceAll("@Nullable\\s{4,}", "@Nullable "); 29 | 30 | file.setText(fileContents, 'UTF-8'); 31 | } 32 | 33 | javadocJar.dependsOn javadocCleanup 34 | build.dependsOn javadocCleanup -------------------------------------------------------------------------------- /gradle/push_javadoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ---------------------------------------------------------- 3 | # Automatically push back the generated JavaDocs to gh-pages 4 | # ---------------------------------------------------------- 5 | # based on https://gist.github.com/willprice/e07efd73fb7f13f917ea 6 | 7 | # specify the common address for the repository 8 | targetRepo=github.com/ReactiveX/RxJava.git 9 | # ======================================================================= 10 | 11 | # only for main pushes, for now 12 | if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then 13 | echo -e "Pull request detected, skipping JavaDocs pushback." 14 | exit 0 15 | fi 16 | 17 | # get the current build tag if any 18 | buildTag="$TRAVIS_TAG" 19 | echo -e "Travis tag: '$buildTag'" 20 | 21 | if [ "$buildTag" == "" ]; then 22 | buildTag="snapshot" 23 | else 24 | buildTag="${buildTag:1}" 25 | fi 26 | 27 | echo -e "JavaDocs pushback for tag: $buildTag" 28 | 29 | # check if the token is actually there 30 | if [ "$GITHUB_TOKEN" == "" ]; then 31 | echo -e "No access to GitHub, skipping JavaDocs pushback." 32 | exit 0 33 | fi 34 | 35 | # prepare the git information 36 | git config --global user.email "travis@travis-ci.org" 37 | git config --global user.name "Travis CI" 38 | 39 | # setup the remote 40 | echo -e "Adding the target repository to git" 41 | git remote add origin-pages https://${GITHUB_TOKEN}@${targetRepo} > /dev/null 2>&1 42 | 43 | # stash changes due to chmod 44 | echo -e "Stashing any local non-ignored changes" 45 | git stash 46 | 47 | # get the gh-pages 48 | echo -e "Update branches and checking out gh-pages" 49 | git fetch --all 50 | git branch -a 51 | git checkout -b gh-pages origin-pages/gh-pages 52 | 53 | # releases should update 2 extra locations 54 | if [ "$buildTag" != "snapshot" ]; then 55 | # for releases, add a new directory with the new version 56 | # and carefully replace the others 57 | 58 | # 1.) main javadoc 59 | # ---------------- 60 | # remove the io subdir 61 | echo -e "Removing javadoc/io" 62 | rm -r javadoc/io 63 | 64 | # remove the html files 65 | echo -e "Removing javadoc/*.html" 66 | rm javadoc/*.html 67 | 68 | # copy the new doc 69 | echo -e "Copying to javadoc/" 70 | yes | cp -rf ./build/docs/javadoc/ . 71 | 72 | # 2.) 2.x javadoc 73 | # remove the io subdir 74 | echo -e "Removing 2.x/javadoc/io" 75 | rm -r 2.x/javadoc/io 76 | 77 | # remove the html files 78 | echo -e "Removing 2.x/javadoc/*.html" 79 | rm 2.x/javadoc/*.html 80 | 81 | # copy the new doc 82 | echo -e "Copying to 2.x/javadoc/" 83 | yes | cp -rf ./build/docs/javadoc/ 2.x/ 84 | fi 85 | 86 | # 3.) create a version/snapshot specific copy of the docs 87 | # clear the existing tag 88 | echo -e "Removing to 2.x/javadoc/${buildTag}" 89 | rm -r 2.x/javadoc/${buildTag} 90 | 91 | # copy the new doc 92 | echo -e "Copying to 2.x/javadoc/${buildTag}" 93 | yes | cp -rf ./build/docs/javadoc/ 2.x/javadoc/${buildTag}/ 94 | 95 | 96 | # stage all changed and new files 97 | echo -e "Staging new files" 98 | git add *.html 99 | git add *.css 100 | git add *.js 101 | git add *package-list* 102 | 103 | # remove tracked but deleted files 104 | echo -e "Removing deleted files" 105 | git add -u 106 | 107 | # commit all 108 | echo -e "commit Travis build: $TRAVIS_BUILD_NUMBER for $buildTag" 109 | git commit --message "Travis build: $TRAVIS_BUILD_NUMBER for $buildTag" 110 | 111 | # debug file list 112 | #find -name "*.html" 113 | 114 | # push it 115 | echo -e "Pushing back changes." 116 | git push --quiet --set-upstream origin-pages gh-pages 117 | 118 | 119 | # we are done 120 | echo -e "JavaDocs pushback complete." -------------------------------------------------------------------------------- /gradle/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | /* 3 | Overall document style 4 | */ 5 | 6 | @import url('resources/fonts/dejavu.css'); 7 | 8 | body { 9 | background-color:#ffffff; 10 | color:#353833; 11 | font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; 12 | font-size:14px; 13 | margin:0; 14 | } 15 | a:link, a:visited { 16 | text-decoration:none; 17 | color:#4A6782; 18 | } 19 | a:hover, a:focus { 20 | text-decoration:none; 21 | color:#bb7a2a; 22 | } 23 | a:active { 24 | text-decoration:none; 25 | color:#4A6782; 26 | } 27 | a[name] { 28 | color:#353833; 29 | } 30 | a[name]:hover { 31 | text-decoration:none; 32 | color:#353833; 33 | } 34 | pre { 35 | font-family:'DejaVu Sans Mono', monospace; 36 | font-size:14px; 37 | } 38 | h1 { 39 | font-size:20px; 40 | } 41 | h2 { 42 | font-size:18px; 43 | } 44 | h3 { 45 | font-size:16px; 46 | font-style:italic; 47 | } 48 | h4 { 49 | font-size:13px; 50 | } 51 | h5 { 52 | font-size:12px; 53 | } 54 | h6 { 55 | font-size:11px; 56 | } 57 | ul { 58 | list-style-type:disc; 59 | } 60 | code, tt { 61 | font-family:'DejaVu Sans Mono', monospace; 62 | font-size:14px; 63 | padding-top:4px; 64 | margin-top:8px; 65 | line-height:1.4em; 66 | } 67 | dt code { 68 | font-family:'DejaVu Sans Mono', monospace; 69 | font-size:14px; 70 | padding-top:4px; 71 | } 72 | table tr td dt code { 73 | font-family:'DejaVu Sans Mono', monospace; 74 | font-size:14px; 75 | vertical-align:top; 76 | padding-top:4px; 77 | } 78 | sup { 79 | font-size:8px; 80 | } 81 | /* 82 | Document title and Copyright styles 83 | */ 84 | .clear { 85 | clear:both; 86 | height:0px; 87 | overflow:hidden; 88 | } 89 | .aboutLanguage { 90 | float:right; 91 | padding:0px 21px; 92 | font-size:11px; 93 | z-index:200; 94 | margin-top:-9px; 95 | } 96 | .legalCopy { 97 | margin-left:.5em; 98 | } 99 | .bar a, .bar a:link, .bar a:visited, .bar a:active { 100 | color:#FFFFFF; 101 | text-decoration:none; 102 | } 103 | .bar a:hover, .bar a:focus { 104 | color:#bb7a2a; 105 | } 106 | .tab { 107 | background-color:#0066FF; 108 | color:#ffffff; 109 | padding:8px; 110 | width:5em; 111 | font-weight:bold; 112 | } 113 | /* 114 | Navigation bar styles 115 | */ 116 | .bar { 117 | background-color:#4D7A97; 118 | color:#FFFFFF; 119 | padding:.8em .5em .4em .8em; 120 | height:auto;/*height:1.8em;*/ 121 | font-size:11px; 122 | margin:0; 123 | } 124 | .topNav { 125 | background-color:#4D7A97; 126 | color:#FFFFFF; 127 | float:left; 128 | padding:0; 129 | width:100%; 130 | clear:right; 131 | height:2.8em; 132 | padding-top:10px; 133 | overflow:hidden; 134 | font-size:12px; 135 | } 136 | .bottomNav { 137 | margin-top:10px; 138 | background-color:#4D7A97; 139 | color:#FFFFFF; 140 | float:left; 141 | padding:0; 142 | width:100%; 143 | clear:right; 144 | height:2.8em; 145 | padding-top:10px; 146 | overflow:hidden; 147 | font-size:12px; 148 | } 149 | .subNav { 150 | background-color:#dee3e9; 151 | float:left; 152 | width:100%; 153 | overflow:hidden; 154 | font-size:12px; 155 | } 156 | .subNav div { 157 | clear:left; 158 | float:left; 159 | padding:0 0 5px 6px; 160 | text-transform:uppercase; 161 | } 162 | ul.navList, ul.subNavList { 163 | float:left; 164 | margin:0 25px 0 0; 165 | padding:0; 166 | } 167 | ul.navList li{ 168 | list-style:none; 169 | float:left; 170 | padding: 5px 6px; 171 | text-transform:uppercase; 172 | } 173 | ul.subNavList li{ 174 | list-style:none; 175 | float:left; 176 | } 177 | .topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { 178 | color:#FFFFFF; 179 | text-decoration:none; 180 | text-transform:uppercase; 181 | } 182 | .topNav a:hover, .bottomNav a:hover { 183 | text-decoration:none; 184 | color:#bb7a2a; 185 | text-transform:uppercase; 186 | } 187 | .navBarCell1Rev { 188 | background-color:#F8981D; 189 | color:#253441; 190 | margin: auto 5px; 191 | } 192 | .skipNav { 193 | position:absolute; 194 | top:auto; 195 | left:-9999px; 196 | overflow:hidden; 197 | } 198 | /* 199 | Page header and footer styles 200 | */ 201 | .header, .footer { 202 | clear:both; 203 | margin:0 20px; 204 | padding:5px 0 0 0; 205 | } 206 | .indexHeader { 207 | margin:10px; 208 | position:relative; 209 | } 210 | .indexHeader span{ 211 | margin-right:15px; 212 | } 213 | .indexHeader h1 { 214 | font-size:13px; 215 | } 216 | .title { 217 | color:#2c4557; 218 | margin:10px 0; 219 | } 220 | .subTitle { 221 | margin:5px 0 0 0; 222 | } 223 | .header ul { 224 | margin:0 0 15px 0; 225 | padding:0; 226 | } 227 | .footer ul { 228 | margin:20px 0 5px 0; 229 | } 230 | .header ul li, .footer ul li { 231 | list-style:none; 232 | font-size:13px; 233 | } 234 | /* 235 | Heading styles 236 | */ 237 | div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { 238 | background-color:#dee3e9; 239 | border:1px solid #d0d9e0; 240 | margin:0 0 6px -8px; 241 | padding:7px 5px; 242 | } 243 | ul.blockList ul.blockList ul.blockList li.blockList h3 { 244 | background-color:#dee3e9; 245 | border:1px solid #d0d9e0; 246 | margin:0 0 6px -8px; 247 | padding:7px 5px; 248 | } 249 | ul.blockList ul.blockList li.blockList h3 { 250 | padding:0; 251 | margin:15px 0; 252 | } 253 | ul.blockList li.blockList h2 { 254 | padding:0px 0 20px 0; 255 | } 256 | /* 257 | Page layout container styles 258 | */ 259 | .contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { 260 | clear:both; 261 | padding:10px 20px; 262 | position:relative; 263 | } 264 | .indexContainer { 265 | margin:10px; 266 | position:relative; 267 | font-size:12px; 268 | } 269 | .indexContainer h2 { 270 | font-size:13px; 271 | padding:0 0 3px 0; 272 | } 273 | .indexContainer ul { 274 | margin:0; 275 | padding:0; 276 | } 277 | .indexContainer ul li { 278 | list-style:none; 279 | padding-top:2px; 280 | } 281 | .contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { 282 | font-size:12px; 283 | font-weight:bold; 284 | margin:10px 0 0 0; 285 | color:#4E4E4E; 286 | } 287 | .contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { 288 | /* margin:5px 0 10px 0px; */ 289 | font-size:14px; 290 | font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; 291 | } 292 | .serializedFormContainer dl.nameValue dt { 293 | margin-left:1px; 294 | font-size:1.1em; 295 | display:inline; 296 | font-weight:bold; 297 | } 298 | .serializedFormContainer dl.nameValue dd { 299 | margin:0 0 0 1px; 300 | font-size:1.1em; 301 | display:inline; 302 | } 303 | /* 304 | List styles 305 | */ 306 | ul.horizontal li { 307 | display:inline; 308 | font-size:0.9em; 309 | } 310 | ul.inheritance { 311 | margin:0; 312 | padding:0; 313 | } 314 | ul.inheritance li { 315 | display:inline; 316 | list-style:none; 317 | } 318 | ul.inheritance li ul.inheritance { 319 | margin-left:15px; 320 | padding-left:15px; 321 | padding-top:1px; 322 | } 323 | ul.blockList, ul.blockListLast { 324 | margin:10px 0 10px 0; 325 | padding:0; 326 | } 327 | ul.blockList li.blockList, ul.blockListLast li.blockList { 328 | list-style:none; 329 | margin-bottom:15px; 330 | line-height:1.4; 331 | } 332 | ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { 333 | padding:0px 20px 5px 10px; 334 | border:1px solid #ededed; 335 | background-color:#f8f8f8; 336 | } 337 | ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { 338 | padding:0 0 5px 8px; 339 | background-color:#ffffff; 340 | border:none; 341 | } 342 | ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { 343 | margin-left:0; 344 | padding-left:0; 345 | padding-bottom:15px; 346 | border:none; 347 | } 348 | ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { 349 | list-style:none; 350 | border-bottom:none; 351 | padding-bottom:0; 352 | } 353 | table tr td dl, table tr td dl dt, table tr td dl dd { 354 | margin-top:0; 355 | margin-bottom:1px; 356 | } 357 | /* 358 | Table styles 359 | */ 360 | .overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { 361 | width:100%; 362 | border-left:1px solid #EEE; 363 | border-right:1px solid #EEE; 364 | border-bottom:1px solid #EEE; 365 | } 366 | .overviewSummary, .memberSummary { 367 | padding:0px; 368 | } 369 | .overviewSummary caption, .memberSummary caption, .typeSummary caption, 370 | .useSummary caption, .constantsSummary caption, .deprecatedSummary caption { 371 | position:relative; 372 | text-align:left; 373 | background-repeat:no-repeat; 374 | color:#253441; 375 | font-weight:bold; 376 | clear:none; 377 | overflow:hidden; 378 | padding:0px; 379 | padding-top:10px; 380 | padding-left:1px; 381 | margin:0px; 382 | white-space:pre; 383 | } 384 | .overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, 385 | .useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, 386 | .overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, 387 | .useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, 388 | .overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, 389 | .useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, 390 | .overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, 391 | .useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { 392 | color:#FFFFFF; 393 | } 394 | .overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, 395 | .useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { 396 | white-space:nowrap; 397 | padding-top:5px; 398 | padding-left:12px; 399 | padding-right:12px; 400 | padding-bottom:7px; 401 | display:inline-block; 402 | float:left; 403 | background-color:#F8981D; 404 | border: none; 405 | height:16px; 406 | } 407 | .memberSummary caption span.activeTableTab span { 408 | white-space:nowrap; 409 | padding-top:5px; 410 | padding-left:12px; 411 | padding-right:12px; 412 | margin-right:3px; 413 | display:inline-block; 414 | float:left; 415 | background-color:#F8981D; 416 | height:16px; 417 | } 418 | .memberSummary caption span.tableTab span { 419 | white-space:nowrap; 420 | padding-top:5px; 421 | padding-left:12px; 422 | padding-right:12px; 423 | margin-right:3px; 424 | display:inline-block; 425 | float:left; 426 | background-color:#4D7A97; 427 | height:16px; 428 | } 429 | .memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { 430 | padding-top:0px; 431 | padding-left:0px; 432 | padding-right:0px; 433 | background-image:none; 434 | float:none; 435 | display:inline; 436 | } 437 | .overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, 438 | .useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { 439 | display:none; 440 | width:5px; 441 | position:relative; 442 | float:left; 443 | background-color:#F8981D; 444 | } 445 | .memberSummary .activeTableTab .tabEnd { 446 | display:none; 447 | width:5px; 448 | margin-right:3px; 449 | position:relative; 450 | float:left; 451 | background-color:#F8981D; 452 | } 453 | .memberSummary .tableTab .tabEnd { 454 | display:none; 455 | width:5px; 456 | margin-right:3px; 457 | position:relative; 458 | background-color:#4D7A97; 459 | float:left; 460 | 461 | } 462 | .overviewSummary td, .memberSummary td, .typeSummary td, 463 | .useSummary td, .constantsSummary td, .deprecatedSummary td { 464 | text-align:left; 465 | padding:0px 0px 12px 10px; 466 | } 467 | th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, 468 | td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ 469 | vertical-align:top; 470 | padding-right:0px; 471 | padding-top:8px; 472 | padding-bottom:3px; 473 | } 474 | th.colFirst, th.colLast, th.colOne, .constantsSummary th { 475 | background:#dee3e9; 476 | text-align:left; 477 | padding:8px 3px 3px 7px; 478 | } 479 | td.colFirst, th.colFirst { 480 | white-space:nowrap; 481 | font-size:13px; 482 | } 483 | td.colLast, th.colLast { 484 | font-size:13px; 485 | } 486 | td.colOne, th.colOne { 487 | font-size:13px; 488 | } 489 | .overviewSummary td.colFirst, .overviewSummary th.colFirst, 490 | .useSummary td.colFirst, .useSummary th.colFirst, 491 | .overviewSummary td.colOne, .overviewSummary th.colOne, 492 | .memberSummary td.colFirst, .memberSummary th.colFirst, 493 | .memberSummary td.colOne, .memberSummary th.colOne, 494 | .typeSummary td.colFirst{ 495 | width:25%; 496 | vertical-align:top; 497 | } 498 | td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { 499 | font-weight:bold; 500 | } 501 | .tableSubHeadingColor { 502 | background-color:#EEEEFF; 503 | } 504 | .altColor { 505 | background-color:#FFFFFF; 506 | } 507 | .rowColor { 508 | background-color:#EEEEEF; 509 | } 510 | /* 511 | Content styles 512 | */ 513 | .description pre { 514 | margin-top:0; 515 | } 516 | .deprecatedContent { 517 | margin:0; 518 | padding:10px 0; 519 | } 520 | .docSummary { 521 | padding:0; 522 | } 523 | 524 | ul.blockList ul.blockList ul.blockList li.blockList h3 { 525 | font-style:normal; 526 | } 527 | 528 | div.block { 529 | font-size:14px; 530 | font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; 531 | } 532 | 533 | td.colLast div { 534 | padding-top:0px; 535 | } 536 | 537 | td.colLast a { 538 | padding-bottom:3px; 539 | } 540 | /* 541 | Formatting effect styles 542 | */ 543 | .sourceLineNo { 544 | color:green; 545 | padding:0 30px 0 0; 546 | } 547 | h1.hidden { 548 | visibility:hidden; 549 | overflow:hidden; 550 | font-size:10px; 551 | } 552 | .block { 553 | display:block; 554 | margin:3px 10px 2px 0px; 555 | color:#474747; 556 | } 557 | .deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, 558 | .overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, 559 | .seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { 560 | font-weight:bold; 561 | } 562 | .deprecationComment, .emphasizedPhrase, .interfaceName { 563 | font-style:italic; 564 | } 565 | 566 | div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, 567 | div.block div.block span.interfaceName { 568 | font-style:normal; 569 | } 570 | 571 | div.contentContainer ul.blockList li.blockList h2{ 572 | padding-bottom:0px; 573 | } 574 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-bin.zip 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /lombok.config: -------------------------------------------------------------------------------- 1 | lombok.log.fieldName=logger -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'chainbase' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) [2016] [ ] This file is part of the ethereumJ library. 3 | * 4 | * The ethereumJ library is free software: you can redistribute it and/or modify it under the terms 5 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either 6 | * version 3 of the License, or (at your option) any later version. 7 | * 8 | * The ethereumJ library is distributed in the hope that it will be useful, but WITHOUT ANY 9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 10 | * PURPOSE. See the GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License along with the ethereumJ 13 | * library. If not, see . 14 | */ 15 | 16 | package org.tron.common.storage.leveldb; 17 | 18 | import static org.fusesource.leveldbjni.JniDBFactory.factory; 19 | 20 | import com.google.common.collect.Sets; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.nio.file.Files; 24 | import java.nio.file.Path; 25 | import java.nio.file.Paths; 26 | import java.util.Collections; 27 | import java.util.HashMap; 28 | import java.util.Map; 29 | import java.util.Map.Entry; 30 | import java.util.Objects; 31 | import java.util.Set; 32 | import java.util.concurrent.locks.ReadWriteLock; 33 | import java.util.concurrent.locks.ReentrantReadWriteLock; 34 | import java.util.stream.Stream; 35 | import java.util.stream.StreamSupport; 36 | import lombok.NoArgsConstructor; 37 | import lombok.extern.slf4j.Slf4j; 38 | import org.iq80.leveldb.CompressionType; 39 | import org.iq80.leveldb.DB; 40 | import org.iq80.leveldb.DBException; 41 | import org.iq80.leveldb.DBIterator; 42 | import org.iq80.leveldb.Options; 43 | import org.iq80.leveldb.WriteBatch; 44 | import org.iq80.leveldb.WriteOptions; 45 | import org.tron.core.db.common.DbSourceInter; 46 | import org.tron.core.db.common.iterator.StoreIterator; 47 | import org.tron.core.db2.common.Instance; 48 | import org.tron.utils.FileUtil; 49 | 50 | @Slf4j(topic = "DB") 51 | @NoArgsConstructor 52 | public class LevelDbDataSourceImpl implements DbSourceInter, 53 | Iterable>, Instance { 54 | 55 | private String dataBaseName; 56 | private DB database; 57 | private boolean alive; 58 | private String parentPath; 59 | private Options options; 60 | private WriteOptions writeOptions; 61 | private ReadWriteLock resetDbLock = new ReentrantReadWriteLock(); 62 | 63 | /** 64 | * constructor. 65 | */ 66 | public LevelDbDataSourceImpl(String parentPath, String dataBaseName, Options options, WriteOptions writeOptions) { 67 | this.parentPath = parentPath; 68 | this.dataBaseName = dataBaseName; 69 | this.options = options; 70 | this.writeOptions = writeOptions; 71 | initDB(); 72 | } 73 | 74 | @Override 75 | public void initDB() { 76 | resetDbLock.writeLock().lock(); 77 | try { 78 | logger.debug("~> LevelDbDataSourceImpl.initDB(): " + dataBaseName); 79 | 80 | if (isAlive()) { 81 | return; 82 | } 83 | 84 | if (dataBaseName == null) { 85 | throw new NullPointerException("no name set to the dbStore"); 86 | } 87 | 88 | try { 89 | openDatabase(options); 90 | alive = true; 91 | } catch (IOException ioe) { 92 | throw new RuntimeException("Can't initialize database", ioe); 93 | } 94 | } finally { 95 | resetDbLock.writeLock().unlock(); 96 | } 97 | } 98 | 99 | private void openDatabase(Options dbOptions) throws IOException { 100 | final Path dbPath = getDbPath(); 101 | if (!Files.isSymbolicLink(dbPath.getParent())) { 102 | Files.createDirectories(dbPath.getParent()); 103 | } 104 | try { 105 | database = factory.open(dbPath.toFile(), dbOptions); 106 | } catch (IOException e) { 107 | if (e.getMessage().contains("Corruption:")) { 108 | factory.repair(dbPath.toFile(), dbOptions); 109 | database = factory.open(dbPath.toFile(), dbOptions); 110 | } else { 111 | throw e; 112 | } 113 | } 114 | } 115 | 116 | @Deprecated 117 | private Options createDbOptions() { 118 | Options dbOptions = new Options(); 119 | dbOptions.createIfMissing(true); 120 | dbOptions.compressionType(CompressionType.NONE); 121 | dbOptions.blockSize(10 * 1024 * 1024); 122 | dbOptions.writeBufferSize(10 * 1024 * 1024); 123 | dbOptions.cacheSize(0); 124 | dbOptions.paranoidChecks(true); 125 | dbOptions.verifyChecksums(true); 126 | dbOptions.maxOpenFiles(32); 127 | return dbOptions; 128 | } 129 | 130 | public Path getDbPath() { 131 | return Paths.get(parentPath, dataBaseName); 132 | } 133 | 134 | /** 135 | * reset database. 136 | */ 137 | public void resetDb() { 138 | closeDB(); 139 | FileUtil.recursiveDelete(getDbPath().toString()); 140 | initDB(); 141 | } 142 | 143 | @Override 144 | public boolean isAlive() { 145 | return alive; 146 | } 147 | 148 | /** 149 | * destroy database. 150 | */ 151 | public void destroyDb(File fileLocation) { 152 | resetDbLock.writeLock().lock(); 153 | try { 154 | logger.debug("Destroying existing database: " + fileLocation); 155 | Options options = new Options(); 156 | try { 157 | factory.destroy(fileLocation, options); 158 | } catch (IOException e) { 159 | logger.error(e.getMessage(), e); 160 | } 161 | } finally { 162 | resetDbLock.writeLock().unlock(); 163 | } 164 | } 165 | 166 | @Override 167 | public String getDBName() { 168 | return dataBaseName; 169 | } 170 | 171 | @Override 172 | public void setDBName(String name) { 173 | this.dataBaseName = name; 174 | } 175 | 176 | @Override 177 | public byte[] getData(byte[] key) { 178 | resetDbLock.readLock().lock(); 179 | try { 180 | return database.get(key); 181 | } catch (DBException e) { 182 | logger.debug(e.getMessage(), e); 183 | } finally { 184 | resetDbLock.readLock().unlock(); 185 | } 186 | return null; 187 | } 188 | 189 | @Override 190 | public void putData(byte[] key, byte[] value) { 191 | resetDbLock.readLock().lock(); 192 | try { 193 | database.put(key, value, writeOptions); 194 | } finally { 195 | resetDbLock.readLock().unlock(); 196 | } 197 | } 198 | 199 | @Override 200 | public void deleteData(byte[] key) { 201 | resetDbLock.readLock().lock(); 202 | try { 203 | database.delete(key, writeOptions); 204 | } finally { 205 | resetDbLock.readLock().unlock(); 206 | } 207 | } 208 | 209 | @Deprecated 210 | @Override 211 | public Set allKeys() { 212 | resetDbLock.readLock().lock(); 213 | try (DBIterator iterator = database.iterator()) { 214 | Set result = Sets.newHashSet(); 215 | for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { 216 | result.add(iterator.peekNext().getKey()); 217 | } 218 | return result; 219 | } catch (IOException e) { 220 | throw new RuntimeException(e); 221 | } finally { 222 | resetDbLock.readLock().unlock(); 223 | } 224 | } 225 | 226 | @Deprecated 227 | @Override 228 | public Set allValues() { 229 | resetDbLock.readLock().lock(); 230 | try (DBIterator iterator = database.iterator()) { 231 | Set result = Sets.newHashSet(); 232 | for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { 233 | result.add(iterator.peekNext().getValue()); 234 | } 235 | return result; 236 | } catch (IOException e) { 237 | throw new RuntimeException(e); 238 | } finally { 239 | resetDbLock.readLock().unlock(); 240 | } 241 | } 242 | 243 | public Set getlatestValues(long limit) { 244 | if (limit <= 0) { 245 | return Sets.newHashSet(); 246 | } 247 | resetDbLock.readLock().lock(); 248 | try (DBIterator iterator = database.iterator()) { 249 | Set result = Sets.newHashSet(); 250 | long i = 0; 251 | iterator.seekToLast(); 252 | if (iterator.hasNext()) { 253 | result.add(iterator.peekNext().getValue()); 254 | i++; 255 | } 256 | for (; iterator.hasPrev() && i++ < limit; iterator.prev()) { 257 | result.add(iterator.peekPrev().getValue()); 258 | } 259 | return result; 260 | } catch (IOException e) { 261 | throw new RuntimeException(e); 262 | } finally { 263 | resetDbLock.readLock().unlock(); 264 | } 265 | } 266 | 267 | public Set getValuesNext(byte[] key, long limit) { 268 | if (limit <= 0) { 269 | return Sets.newHashSet(); 270 | } 271 | resetDbLock.readLock().lock(); 272 | try (DBIterator iterator = database.iterator()) { 273 | Set result = Sets.newHashSet(); 274 | long i = 0; 275 | for (iterator.seek(key); iterator.hasNext() && i++ < limit; iterator.next()) { 276 | result.add(iterator.peekNext().getValue()); 277 | } 278 | return result; 279 | } catch (IOException e) { 280 | throw new RuntimeException(e); 281 | } finally { 282 | resetDbLock.readLock().unlock(); 283 | } 284 | } 285 | 286 | public Map getNext(byte[] key, long limit) { 287 | if (limit <= 0) { 288 | return Collections.emptyMap(); 289 | } 290 | resetDbLock.readLock().lock(); 291 | try (DBIterator iterator = database.iterator()) { 292 | Map result = new HashMap<>(); 293 | long i = 0; 294 | for (iterator.seek(key); iterator.hasNext() && i++ < limit; iterator.next()) { 295 | Entry entry = iterator.peekNext(); 296 | result.put(entry.getKey(), entry.getValue()); 297 | } 298 | return result; 299 | } catch (IOException e) { 300 | throw new RuntimeException(e); 301 | } finally { 302 | resetDbLock.readLock().unlock(); 303 | } 304 | } 305 | 306 | public Set getValuesPrev(byte[] key, long limit) { 307 | if (limit <= 0) { 308 | return Sets.newHashSet(); 309 | } 310 | resetDbLock.readLock().lock(); 311 | try (DBIterator iterator = database.iterator()) { 312 | Set result = Sets.newHashSet(); 313 | long i = 0; 314 | byte[] data = getData(key); 315 | if (Objects.nonNull(data)) { 316 | result.add(data); 317 | i++; 318 | } 319 | for (iterator.seek(key); iterator.hasPrev() && i++ < limit; iterator.prev()) { 320 | result.add(iterator.peekPrev().getValue()); 321 | } 322 | return result; 323 | } catch (IOException e) { 324 | throw new RuntimeException(e); 325 | } finally { 326 | resetDbLock.readLock().unlock(); 327 | } 328 | } 329 | 330 | @Override 331 | public long getTotal() throws RuntimeException { 332 | resetDbLock.readLock().lock(); 333 | try (DBIterator iterator = database.iterator()) { 334 | long total = 0; 335 | for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { 336 | total++; 337 | } 338 | return total; 339 | } catch (IOException e) { 340 | throw new RuntimeException(e); 341 | } finally { 342 | resetDbLock.readLock().unlock(); 343 | } 344 | } 345 | 346 | private void updateByBatchInner(Map rows) throws Exception { 347 | try (WriteBatch batch = database.createWriteBatch()) { 348 | rows.forEach((key, value) -> { 349 | if (value == null) { 350 | batch.delete(key); 351 | } else { 352 | batch.put(key, value); 353 | } 354 | }); 355 | database.write(batch, writeOptions); 356 | } 357 | } 358 | 359 | @Override 360 | public void updateByBatch(Map rows) { 361 | resetDbLock.readLock().lock(); 362 | try { 363 | updateByBatchInner(rows); 364 | } catch (Exception e) { 365 | try { 366 | updateByBatchInner(rows); 367 | } catch (Exception e1) { 368 | throw new RuntimeException(e); 369 | } 370 | } finally { 371 | resetDbLock.readLock().unlock(); 372 | } 373 | } 374 | 375 | @Override 376 | public boolean flush() { 377 | return false; 378 | } 379 | 380 | @Override 381 | public void closeDB() { 382 | resetDbLock.writeLock().lock(); 383 | try { 384 | if (!isAlive()) { 385 | return; 386 | } 387 | database.close(); 388 | alive = false; 389 | } catch (IOException e) { 390 | logger.error("Failed to find the dbStore file on the closeDB: {} ", dataBaseName); 391 | } finally { 392 | resetDbLock.writeLock().unlock(); 393 | } 394 | } 395 | 396 | @Override 397 | public org.tron.core.db.common.iterator.DBIterator iterator() { 398 | return new StoreIterator(database.iterator()); 399 | } 400 | 401 | public Stream> stream() { 402 | return StreamSupport.stream(spliterator(), false); 403 | } 404 | 405 | public Stream> parallelStream() { 406 | return StreamSupport.stream(spliterator(), true); 407 | } 408 | 409 | @Override 410 | public LevelDbDataSourceImpl newInstance() { 411 | return new LevelDbDataSourceImpl(parentPath, dataBaseName, options, writeOptions); 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db/RevokingDatabase.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db; 2 | 3 | import org.tron.core.db2.common.IRevokingDB; 4 | import org.tron.core.db2.core.ISession; 5 | import org.tron.core.exception.RevokingStoreIllegalStateException; 6 | 7 | public interface RevokingDatabase { 8 | 9 | ISession buildSession(); 10 | 11 | ISession buildSession(boolean forceEnable); 12 | 13 | void setMode(boolean mode); 14 | 15 | void add(IRevokingDB revokingDB); 16 | 17 | void merge() throws RevokingStoreIllegalStateException; 18 | 19 | void revoke() throws RevokingStoreIllegalStateException; 20 | 21 | void commit() throws RevokingStoreIllegalStateException; 22 | 23 | void pop() throws RevokingStoreIllegalStateException; 24 | 25 | void fastPop() throws RevokingStoreIllegalStateException; 26 | 27 | void enable(); 28 | 29 | int size(); 30 | 31 | void check(); 32 | 33 | void setMaxSize(int maxSize); 34 | 35 | void disable(); 36 | 37 | void setMaxFlushCount(int maxFlushCount); 38 | 39 | void shutdown(); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db/common/BatchSourceInter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) [2016] [ ] 3 | * This file is part of the ethereumJ library. 4 | * 5 | * The ethereumJ library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The ethereumJ library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with the ethereumJ library. If not, see . 17 | */ 18 | 19 | package org.tron.core.db.common; 20 | 21 | import java.util.Map; 22 | import org.iq80.leveldb.WriteOptions; 23 | 24 | 25 | public interface BatchSourceInter extends SourceInter { 26 | 27 | void updateByBatch(Map rows); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db/common/DbSourceInter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) [2016] [ ] 3 | * This file is part of the ethereumJ library. 4 | * 5 | * The ethereumJ library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The ethereumJ library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with the ethereumJ library. If not, see . 17 | */ 18 | package org.tron.core.db.common; 19 | 20 | import java.util.Set; 21 | 22 | 23 | public interface DbSourceInter extends BatchSourceInter { 24 | 25 | String getDBName(); 26 | 27 | void setDBName(String name); 28 | 29 | void initDB(); 30 | 31 | boolean isAlive(); 32 | 33 | void closeDB(); 34 | 35 | void resetDb(); 36 | 37 | Set allKeys() throws RuntimeException; 38 | 39 | Set allValues() throws RuntimeException; 40 | 41 | long getTotal() throws RuntimeException; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db/common/SourceInter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) [2016] [ ] 3 | * This file is part of the ethereumJ library. 4 | * 5 | * The ethereumJ library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The ethereumJ library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with the ethereumJ library. If not, see . 17 | */ 18 | package org.tron.core.db.common; 19 | 20 | public interface SourceInter { 21 | 22 | void putData(K key, V val); 23 | 24 | V getData(K key); 25 | 26 | void deleteData(K key); 27 | 28 | boolean flush(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db/common/iterator/DBIterator.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db.common.iterator; 2 | 3 | import java.io.Closeable; 4 | import java.util.Iterator; 5 | import java.util.Map.Entry; 6 | 7 | public interface DBIterator extends Iterator>, Closeable { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db/common/iterator/StoreIterator.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db.common.iterator; 2 | 3 | import java.io.IOException; 4 | import java.util.Map.Entry; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.iq80.leveldb.DBIterator; 7 | 8 | @Slf4j(topic = "DB") 9 | public final class StoreIterator implements org.tron.core.db.common.iterator.DBIterator { 10 | 11 | private DBIterator dbIterator; 12 | private boolean first = true; 13 | 14 | public StoreIterator(DBIterator dbIterator) { 15 | this.dbIterator = dbIterator; 16 | } 17 | 18 | @Override 19 | public void close() throws IOException { 20 | dbIterator.close(); 21 | } 22 | 23 | @Override 24 | public boolean hasNext() { 25 | boolean hasNext = false; 26 | // true is first item 27 | try { 28 | if (first) { 29 | dbIterator.seekToFirst(); 30 | first = false; 31 | } 32 | 33 | if (!(hasNext = dbIterator.hasNext())) { // false is last item 34 | dbIterator.close(); 35 | } 36 | } catch (Exception e) { 37 | logger.debug(e.getMessage(), e); 38 | } 39 | 40 | return hasNext; 41 | } 42 | 43 | @Override 44 | public Entry next() { 45 | return dbIterator.next(); 46 | } 47 | 48 | @Override 49 | public void remove() { 50 | throw new UnsupportedOperationException(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/DB.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.Map; 4 | 5 | public interface DB extends Iterable>, Instance> { 6 | V get(K k); 7 | 8 | void put(K k, V v); 9 | 10 | long size(); 11 | 12 | boolean isEmpty(); 13 | 14 | void remove(K k); 15 | 16 | String getDbName(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/Flusher.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.Map; 4 | 5 | public interface Flusher { 6 | void flush(Map batch); 7 | 8 | void close(); 9 | 10 | void reset(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/HashDB.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | 7 | public class HashDB implements DB { 8 | private Map db = new HashMap<>(); 9 | private String name; 10 | 11 | public HashDB(String name) { 12 | this.name = name; 13 | } 14 | 15 | @Override 16 | public Value get(Key key) { 17 | return db.get(key); 18 | } 19 | 20 | @Override 21 | public void put(Key key, Value value) { 22 | db.put(key, value); 23 | } 24 | 25 | @Override 26 | public long size() { 27 | return db.size(); 28 | } 29 | 30 | @Override 31 | public boolean isEmpty() { 32 | return db.isEmpty(); 33 | } 34 | 35 | @Override 36 | public void remove(Key key) { 37 | db.remove(key); 38 | } 39 | 40 | @Override 41 | public String getDbName() { 42 | return name; 43 | } 44 | 45 | @Override 46 | public Iterator> iterator() { 47 | return db.entrySet().iterator(); 48 | } 49 | 50 | @Override 51 | public HashDB newInstance() { 52 | return new HashDB(name); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/IRevokingDB.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.Map; 4 | import java.util.Set; 5 | import org.tron.core.exception.ItemNotFoundException; 6 | 7 | public interface IRevokingDB extends Iterable> { 8 | void put(byte[] key, byte[] newValue); 9 | 10 | void delete(byte[] key); 11 | 12 | boolean has(byte[] key); 13 | 14 | byte[] get(byte[] key) throws ItemNotFoundException; 15 | 16 | byte[] getUnchecked(byte[] key); 17 | 18 | void close(); 19 | 20 | void reset(); 21 | 22 | void setMode(boolean mode); 23 | 24 | // for blockstore 25 | Set getlatestValues(long limit); 26 | 27 | // for blockstore 28 | Set getValuesNext(byte[] key, long limit); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/Instance.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | public interface Instance { 4 | T newInstance(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/Key.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.Arrays; 4 | import lombok.EqualsAndHashCode; 5 | 6 | @EqualsAndHashCode 7 | public final class Key { 8 | 9 | final private WrappedByteArray data; 10 | 11 | private Key(WrappedByteArray data) { 12 | this.data = data; 13 | } 14 | 15 | public static Key copyOf(byte[] bytes) { 16 | return new Key(WrappedByteArray.copyOf(bytes)); 17 | } 18 | 19 | public static Key of(byte[] bytes) { 20 | return new Key(WrappedByteArray.of(bytes)); 21 | } 22 | 23 | public byte[] getBytes() { 24 | byte[] key = data.getBytes(); 25 | if (key == null) { 26 | return null; 27 | } 28 | 29 | return Arrays.copyOf(key, key.length); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/LevelDB.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import com.google.common.collect.Maps; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import lombok.Getter; 7 | import org.iq80.leveldb.WriteOptions; 8 | import org.tron.common.storage.leveldb.LevelDbDataSourceImpl; 9 | import org.tron.core.db2.common.WrappedByteArray; 10 | import org.tron.core.db.common.iterator.DBIterator; 11 | 12 | public class LevelDB implements DB, Flusher { 13 | @Getter 14 | private LevelDbDataSourceImpl db; 15 | 16 | public LevelDB(LevelDbDataSourceImpl db) { 17 | this.db = db; 18 | } 19 | 20 | @Override 21 | public byte[] get(byte[] key) { 22 | return db.getData(key); 23 | } 24 | 25 | @Override 26 | public void put(byte[] key, byte[] value) { 27 | db.putData(key, value); 28 | } 29 | 30 | @Override 31 | public long size() { 32 | return db.getTotal(); 33 | } 34 | 35 | @Override 36 | public boolean isEmpty() { 37 | return size() == 0; 38 | } 39 | 40 | @Override 41 | public void remove(byte[] key) { 42 | db.deleteData(key); 43 | } 44 | 45 | @Override 46 | public String getDbName() { 47 | return db.getDBName(); 48 | } 49 | 50 | @Override 51 | public DBIterator iterator() { 52 | return db.iterator(); 53 | } 54 | 55 | @Override 56 | public void flush(Map batch) { 57 | Map rows = batch.entrySet().stream() 58 | .map(e -> Maps.immutableEntry(e.getKey().getBytes(), e.getValue().getBytes())) 59 | .collect(HashMap::new, (m, k) -> m.put(k.getKey(), k.getValue()), HashMap::putAll); 60 | db.updateByBatch(rows); 61 | } 62 | 63 | @Override 64 | public void close() { 65 | db.closeDB(); 66 | } 67 | @Override 68 | public void reset() { 69 | db.resetDb(); 70 | } 71 | 72 | @Override 73 | public LevelDB newInstance() { 74 | return new LevelDB(db.newInstance()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/TxCacheDB.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import com.google.common.collect.ArrayListMultimap; 4 | import com.google.common.collect.Iterators; 5 | import com.google.common.collect.Maps; 6 | import com.google.common.collect.Multimap; 7 | import com.google.common.primitives.Longs; 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | import java.util.Map.Entry; 11 | import java.util.Set; 12 | import java.util.WeakHashMap; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.tron.core.db2.common.Key; 15 | import org.tron.core.db2.common.WrappedByteArray; 16 | 17 | @Slf4j(topic = "DB") 18 | public class TxCacheDB implements DB, Flusher { 19 | // > 65_536(= 2^16) blocks, that is the number of the reference block 20 | private final int BLOCK_COUNT = 70_000; 21 | 22 | private Map db = new WeakHashMap<>(); 23 | private Multimap blockNumMap = ArrayListMultimap.create(); 24 | private String name; 25 | 26 | public TxCacheDB(String name) { 27 | this.name = name; 28 | } 29 | 30 | @Override 31 | public byte[] get(byte[] key) { 32 | Long v = db.get(Key.of(key)); 33 | return v == null ? null : Longs.toByteArray(v); 34 | } 35 | 36 | @Override 37 | public void put(byte[] key, byte[] value) { 38 | if (key == null || value == null) { 39 | return; 40 | } 41 | 42 | Key k = Key.copyOf(key); 43 | Long v = Longs.fromByteArray(value); 44 | blockNumMap.put(v, k); 45 | db.put(k, v); 46 | removeEldest(); 47 | } 48 | 49 | private void removeEldest() { 50 | Set keys = blockNumMap.keySet(); 51 | if (keys.size() > BLOCK_COUNT) { 52 | keys.stream() 53 | .min(Long::compareTo) 54 | .ifPresent(k -> { 55 | blockNumMap.removeAll(k); 56 | logger.debug("******removeEldest block number:{}, block count:{}", k, keys.size()); 57 | }); 58 | } 59 | } 60 | 61 | @Override 62 | public long size() { 63 | return db.size(); 64 | } 65 | 66 | @Override 67 | public boolean isEmpty() { 68 | return db.isEmpty(); 69 | } 70 | 71 | @Override 72 | public void remove(byte[] key) { 73 | if (key != null) { 74 | db.remove(Key.of(key)); 75 | } 76 | } 77 | 78 | @Override 79 | public String getDbName() { 80 | return name; 81 | } 82 | 83 | @Override 84 | public Iterator> iterator() { 85 | return Iterators.transform(db.entrySet().iterator(), 86 | e -> Maps.immutableEntry(e.getKey().getBytes(), Longs.toByteArray(e.getValue()))); 87 | } 88 | 89 | @Override 90 | public void flush(Map batch) { 91 | batch.forEach((k, v) -> this.put(k.getBytes(), v.getBytes())); 92 | } 93 | 94 | @Override 95 | public void close() { 96 | reset(); 97 | db = null; 98 | blockNumMap = null; 99 | } 100 | 101 | @Override 102 | public void reset() { 103 | db.clear(); 104 | blockNumMap.clear(); 105 | } 106 | 107 | @Override 108 | public TxCacheDB newInstance() { 109 | return new TxCacheDB(name); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/Value.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.Arrays; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.Getter; 6 | 7 | @EqualsAndHashCode(exclude = "operator") 8 | public final class Value { 9 | 10 | public byte[] encode() { 11 | if (data.getBytes() == null) { 12 | return new byte[]{operator.getValue()}; 13 | } 14 | 15 | byte[] r = new byte[1 + data.getBytes().length]; 16 | r[0] = operator.getValue(); 17 | System.arraycopy(data.getBytes(), 0, r, 1, data.getBytes().length); 18 | return r; 19 | } 20 | 21 | public static Value decode(byte[] bytes) { 22 | Operator operator = Operator.valueOf(bytes[0]); 23 | byte[] value = null; 24 | if (bytes.length > 1) { 25 | value = Arrays.copyOfRange(bytes, 1, bytes.length); 26 | } 27 | return Value.of(operator, value); 28 | } 29 | 30 | public enum Operator { 31 | CREATE((byte) 0), 32 | MODIFY((byte) 1), 33 | DELETE((byte) 2), 34 | PUT((byte) 3); 35 | 36 | @Getter 37 | private byte value; 38 | 39 | Operator(byte value) { 40 | this.value = value; 41 | } 42 | 43 | static Operator valueOf(byte b) { 44 | switch (b) { 45 | case 0: 46 | return Operator.CREATE; 47 | case 1: 48 | return Operator.MODIFY; 49 | case 2: 50 | return Operator.DELETE; 51 | case 3: 52 | return Operator.PUT; 53 | default: 54 | return null; 55 | } 56 | } 57 | } 58 | 59 | @Getter 60 | final private Operator operator; 61 | final private WrappedByteArray data; 62 | 63 | private Value(Operator operator, WrappedByteArray data) { 64 | this.operator = operator; 65 | this.data = data; 66 | } 67 | 68 | public static Value copyOf(Operator operator, byte[] data) { 69 | return new Value(operator, WrappedByteArray.copyOf(data)); 70 | } 71 | 72 | public static Value of(Operator operator, byte[] data) { 73 | return new Value(operator, WrappedByteArray.of(data)); 74 | } 75 | 76 | public byte[] getBytes() { 77 | byte[] value = data.getBytes(); 78 | if (value == null) { 79 | return null; 80 | } 81 | 82 | return Arrays.copyOf(value, value.length); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/common/WrappedByteArray.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.common; 2 | 3 | import java.util.Arrays; 4 | import lombok.AccessLevel; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | 8 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 9 | public final class WrappedByteArray { 10 | 11 | @Getter 12 | private byte[] bytes; 13 | 14 | public static WrappedByteArray of(byte[] bytes) { 15 | return new WrappedByteArray(bytes); 16 | } 17 | 18 | public static WrappedByteArray copyOf(byte[] bytes) { 19 | byte[] value = null; 20 | if (bytes != null) { 21 | value = Arrays.copyOf(bytes, bytes.length); 22 | } 23 | 24 | return new WrappedByteArray(value); 25 | } 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if (this == o) { 30 | return true; 31 | } 32 | if (o == null || getClass() != o.getClass()) { 33 | return false; 34 | } 35 | WrappedByteArray byteArray = (WrappedByteArray) o; 36 | return Arrays.equals(bytes, byteArray.bytes); 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return Arrays.hashCode(bytes); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/AbstractSnapshot.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | import java.lang.ref.WeakReference; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.tron.core.db2.common.DB; 7 | 8 | public abstract class AbstractSnapshot implements Snapshot { 9 | @Getter 10 | protected DB db; 11 | @Getter 12 | @Setter 13 | protected Snapshot previous; 14 | 15 | protected WeakReference next; 16 | 17 | @Override 18 | public Snapshot advance() { 19 | return new SnapshotImpl(this); 20 | } 21 | 22 | @Override 23 | public Snapshot getNext() { 24 | return next == null ? null : next.get(); 25 | } 26 | 27 | @Override 28 | public void setNext(Snapshot next) { 29 | this.next = new WeakReference<>(next); 30 | } 31 | 32 | @Override 33 | public String getDbName() { 34 | return db.getDbName(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/Chainbase.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.collect.Streams; 5 | import java.util.Collections; 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | import org.tron.core.db2.common.IRevokingDB; 13 | import org.tron.core.db2.common.LevelDB; 14 | import org.tron.core.db2.common.Value; 15 | import org.tron.core.db2.common.WrappedByteArray; 16 | import org.tron.core.exception.ItemNotFoundException; 17 | import org.tron.utils.ByteUtil; 18 | 19 | public class Chainbase implements IRevokingDB { 20 | 21 | //true:fullnode, false:soliditynode 22 | private ThreadLocal mode = new ThreadLocal<>(); 23 | private Snapshot head; 24 | 25 | public Chainbase(Snapshot head) { 26 | this.head = head; 27 | mode.set(true); 28 | } 29 | 30 | public String getDbName() { 31 | return head.getDbName(); 32 | } 33 | 34 | @Override 35 | public void setMode(boolean mode) { 36 | this.mode.set(mode); 37 | } 38 | 39 | private Snapshot head() { 40 | if (mode.get() == null || mode.get()) { 41 | return head; 42 | } else { 43 | return head.getSolidity(); 44 | } 45 | } 46 | 47 | public synchronized Snapshot getHead() { 48 | return head(); 49 | } 50 | 51 | public synchronized void setHead(Snapshot head) { 52 | this.head = head; 53 | } 54 | 55 | /** 56 | * close the database. 57 | */ 58 | @Override 59 | public synchronized void close() { 60 | head().close(); 61 | } 62 | 63 | @Override 64 | public synchronized void reset() { 65 | head().reset(); 66 | head().close(); 67 | head = head.getRoot().newInstance(); 68 | } 69 | 70 | @Override 71 | public synchronized void put(byte[] key, byte[] value) { 72 | head().put(key, value); 73 | } 74 | 75 | @Override 76 | public synchronized void delete(byte[] key) { 77 | head().remove(key); 78 | } 79 | 80 | @Override 81 | public synchronized byte[] get(byte[] key) throws ItemNotFoundException { 82 | byte[] value = getUnchecked(key); 83 | if (value == null) { 84 | throw new ItemNotFoundException(); 85 | } 86 | 87 | return value; 88 | } 89 | 90 | @Override 91 | public synchronized byte[] getUnchecked(byte[] key) { 92 | return head().get(key); 93 | } 94 | 95 | @Override 96 | public synchronized boolean has(byte[] key) { 97 | return getUnchecked(key) != null; 98 | } 99 | 100 | @Override 101 | public synchronized Iterator> iterator() { 102 | return head().iterator(); 103 | } 104 | 105 | //for blockstore 106 | @Override 107 | public Set getlatestValues(long limit) { 108 | return getlatestValues(head(), limit); 109 | } 110 | 111 | //for blockstore 112 | private synchronized Set getlatestValues(Snapshot head, long limit) { 113 | if (limit <= 0) { 114 | return Collections.emptySet(); 115 | } 116 | 117 | Set result = new HashSet<>(); 118 | Snapshot snapshot = head; 119 | long tmp = limit; 120 | for (; tmp > 0 && snapshot.getPrevious() != null; snapshot = snapshot.getPrevious()) { 121 | if (!((SnapshotImpl) snapshot).db.isEmpty()) { 122 | --tmp; 123 | Streams.stream(((SnapshotImpl) snapshot).db) 124 | .map(Map.Entry::getValue) 125 | .map(Value::getBytes) 126 | .forEach(result::add); 127 | } 128 | } 129 | 130 | if (snapshot.getPrevious() == null && tmp != 0) { 131 | if (((SnapshotRoot) head.getRoot()).db.getClass() == LevelDB.class) { 132 | result.addAll(((LevelDB) ((SnapshotRoot) snapshot).db).getDb().getlatestValues(tmp)); 133 | } 134 | // else if (((SnapshotRoot) head.getRoot()).db.getClass() == RocksDB.class) { 135 | // result.addAll(((RocksDB) ((SnapshotRoot) snapshot).db).getDb().getlatestValues(tmp)); 136 | // } 137 | } 138 | 139 | return result; 140 | } 141 | 142 | //for blockstore 143 | private Set getValuesNext(Snapshot head, byte[] key, long limit) { 144 | if (limit <= 0) { 145 | return Collections.emptySet(); 146 | } 147 | 148 | Map collection = new HashMap<>(); 149 | if (head.getPrevious() != null) { 150 | ((SnapshotImpl) head).collect(collection); 151 | } 152 | 153 | Map levelDBMap = new HashMap<>(); 154 | 155 | if (((SnapshotRoot) head.getRoot()).db.getClass() == LevelDB.class) { 156 | ((LevelDB) ((SnapshotRoot) head.getRoot()).db).getDb().getNext(key, limit).entrySet().stream() 157 | .map(e -> Maps 158 | .immutableEntry(WrappedByteArray.of(e.getKey()), WrappedByteArray.of(e.getValue()))) 159 | .forEach(e -> levelDBMap.put(e.getKey(), e.getValue())); 160 | } 161 | // else if (((SnapshotRoot) head.getRoot()).db.getClass() == RocksDB.class) { 162 | // ((RocksDB) ((SnapshotRoot) head.getRoot()).db).getDb().getNext(key, limit).entrySet().stream() 163 | // .map(e -> Maps 164 | // .immutableEntry(WrappedByteArray.of(e.getKey()), WrappedByteArray.of(e.getValue()))) 165 | // .forEach(e -> levelDBMap.put(e.getKey(), e.getValue())); 166 | // } 167 | 168 | levelDBMap.putAll(collection); 169 | 170 | return levelDBMap.entrySet().stream() 171 | .sorted((e1, e2) -> ByteUtil.compare(e1.getKey().getBytes(), e2.getKey().getBytes())) 172 | .filter(e -> ByteUtil.greaterOrEquals(e.getKey().getBytes(), key)) 173 | .limit(limit) 174 | .map(Map.Entry::getValue) 175 | .map(WrappedByteArray::getBytes) 176 | .collect(Collectors.toSet()); 177 | } 178 | 179 | @Override 180 | public Set getValuesNext(byte[] key, long limit) { 181 | return getValuesNext(head(), key, limit); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/ISession.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | public interface ISession extends AutoCloseable { 4 | 5 | void commit(); 6 | 7 | void revoke(); 8 | 9 | void merge(); 10 | 11 | void destroy(); 12 | 13 | void close(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/Snapshot.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | import java.util.Map; 4 | import org.tron.core.db2.common.Instance; 5 | 6 | public interface Snapshot extends Iterable>, Instance { 7 | 8 | static boolean isRoot(Snapshot snapshot) { 9 | return snapshot != null && snapshot.getClass() == SnapshotRoot.class; 10 | } 11 | 12 | static boolean isImpl(Snapshot snapshot) { 13 | return snapshot != null && snapshot.getClass() == SnapshotImpl.class; 14 | } 15 | 16 | byte[] get(byte[] key); 17 | 18 | void put(byte[] key, byte[] value); 19 | 20 | void remove(byte[] key); 21 | 22 | void merge(Snapshot from); 23 | 24 | Snapshot advance(); 25 | 26 | Snapshot retreat(); 27 | 28 | Snapshot getPrevious(); 29 | 30 | void setPrevious(Snapshot previous); 31 | 32 | Snapshot getRoot(); 33 | 34 | Snapshot getNext(); 35 | 36 | void setNext(Snapshot next); 37 | 38 | Snapshot getSolidity(); 39 | 40 | void close(); 41 | 42 | void reset(); 43 | 44 | void resetSolidity(); 45 | 46 | void updateSolidity(); 47 | 48 | String getDbName(); 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/SnapshotImpl.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | import com.google.common.base.Preconditions; 4 | import com.google.common.collect.Iterators; 5 | import com.google.common.collect.Maps; 6 | import com.google.common.collect.Streams; 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.Iterator; 10 | import java.util.Map; 11 | import java.util.Set; 12 | import lombok.Getter; 13 | import org.tron.core.db2.common.HashDB; 14 | import org.tron.core.db2.common.Key; 15 | import org.tron.core.db2.common.Value; 16 | import org.tron.core.db2.common.WrappedByteArray; 17 | 18 | public class SnapshotImpl extends AbstractSnapshot { 19 | @Getter 20 | protected Snapshot root; 21 | 22 | SnapshotImpl(Snapshot snapshot) { 23 | root = snapshot.getRoot(); 24 | previous = snapshot; 25 | snapshot.setNext(this); 26 | synchronized (this) { 27 | db = new HashDB(SnapshotImpl.class.getSimpleName()); 28 | } 29 | } 30 | 31 | @Override 32 | public byte[] get(byte[] key) { 33 | return get(this, key); 34 | } 35 | 36 | @Override 37 | public void put(byte[] key, byte[] value) { 38 | Preconditions.checkNotNull(key, "key in db is not null."); 39 | Preconditions.checkNotNull(value, "value in db is not null."); 40 | 41 | db.put(Key.copyOf(key), Value.copyOf(Value.Operator.PUT, value)); 42 | } 43 | 44 | @Override 45 | public void remove(byte[] key) { 46 | Preconditions.checkNotNull(key, "key in db is not null."); 47 | db.put(Key.of(key), Value.of(Value.Operator.DELETE, null)); 48 | } 49 | 50 | private byte[] get(Snapshot head, byte[] key) { 51 | Snapshot snapshot = head; 52 | Value value; 53 | while (Snapshot.isImpl(snapshot)) { 54 | if ((value = ((SnapshotImpl) snapshot).db.get(Key.of(key))) != null) { 55 | return value.getBytes(); 56 | } 57 | 58 | snapshot = snapshot.getPrevious(); 59 | } 60 | 61 | return snapshot == null ? null : snapshot.get(key); 62 | } 63 | 64 | // we have a 3x3 matrix of all possibilities when merging previous snapshot and current snapshot : 65 | // -------------- snapshot ------------- 66 | // / \ 67 | // +------------+------------+------------+ 68 | // | put(Y) | delete(Y) | nop | 69 | // +------------+------------+------------+------------+ 70 | // / | put(X) | put(Y) | del | put(X) | 71 | // p +------------+------------+------------+------------+ 72 | // r | delete(X) | put(Y) | del | del | 73 | // e +------------+------------+------------+------------+ 74 | // | | nop | put(Y) | del | nop | 75 | // \ +------------+------------+------------+------------+ 76 | @Override 77 | public void merge(Snapshot from) { 78 | SnapshotImpl fromImpl = (SnapshotImpl) from; 79 | Streams.stream(fromImpl.db).forEach(e -> db.put(e.getKey(), e.getValue())); 80 | } 81 | 82 | @Override 83 | public Snapshot retreat() { 84 | return previous; 85 | } 86 | 87 | @Override 88 | public Snapshot getSolidity() { 89 | return root.getSolidity(); 90 | } 91 | 92 | @Override 93 | public Iterator> iterator() { 94 | Map all = new HashMap<>(); 95 | collect(all); 96 | Set keys = new HashSet<>(all.keySet()); 97 | all.entrySet() 98 | .removeIf(entry -> entry.getValue() == null || entry.getValue().getBytes() == null); 99 | return Iterators.concat( 100 | Iterators.transform(all.entrySet().iterator(), 101 | e -> Maps.immutableEntry(e.getKey().getBytes(), e.getValue().getBytes())), 102 | Iterators.filter(getRoot().iterator(), 103 | e -> !keys.contains(WrappedByteArray.of(e.getKey())))); 104 | } 105 | 106 | synchronized void collect(Map all) { 107 | Snapshot next = getRoot().getNext(); 108 | while (next != null) { 109 | Streams.stream(((SnapshotImpl) next).db) 110 | .forEach(e -> all.put(WrappedByteArray.of(e.getKey().getBytes()), 111 | WrappedByteArray.of(e.getValue().getBytes()))); 112 | next = next.getNext(); 113 | } 114 | } 115 | 116 | @Override 117 | public void close() { 118 | getRoot().close(); 119 | } 120 | 121 | @Override 122 | public void reset() { 123 | getRoot().reset(); 124 | } 125 | 126 | @Override 127 | public void resetSolidity() { 128 | root.resetSolidity(); 129 | } 130 | 131 | @Override 132 | public void updateSolidity() { 133 | root.updateSolidity(); 134 | } 135 | 136 | @Override 137 | public String getDbName() { 138 | return root.getDbName(); 139 | } 140 | 141 | @Override 142 | public Snapshot newInstance() { 143 | return new SnapshotImpl(this); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/SnapshotManager.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.primitives.Bytes; 5 | import com.google.common.primitives.Ints; 6 | import com.google.common.util.concurrent.Futures; 7 | import com.google.common.util.concurrent.ListenableFuture; 8 | import com.google.common.util.concurrent.ListeningExecutorService; 9 | import com.google.common.util.concurrent.MoreExecutors; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.concurrent.ExecutionException; 16 | import java.util.concurrent.Executors; 17 | import java.util.concurrent.Future; 18 | import java.util.concurrent.TimeUnit; 19 | import java.util.concurrent.atomic.AtomicInteger; 20 | import java.util.stream.Collectors; 21 | import lombok.Getter; 22 | import lombok.Setter; 23 | import lombok.extern.slf4j.Slf4j; 24 | import org.iq80.leveldb.Options; 25 | import org.iq80.leveldb.WriteOptions; 26 | import org.tron.common.storage.leveldb.LevelDbDataSourceImpl; 27 | import org.tron.core.db.RevokingDatabase; 28 | import org.tron.core.db2.common.DB; 29 | import org.tron.core.db2.common.IRevokingDB; 30 | import org.tron.core.db2.common.Key; 31 | import org.tron.core.db2.common.Value; 32 | import org.tron.core.db2.common.WrappedByteArray; 33 | import org.tron.core.exception.RevokingStoreIllegalStateException; 34 | 35 | @Slf4j(topic = "DB") 36 | public class SnapshotManager implements RevokingDatabase { 37 | 38 | private static final int DEFAULT_STACK_MAX_SIZE = 256; 39 | public static final int DEFAULT_MAX_FLUSH_COUNT = 500; 40 | public static final int DEFAULT_MIN_FLUSH_COUNT = 1; 41 | @Getter 42 | private List dbs = new ArrayList<>(); 43 | @Getter 44 | private int size = 0; 45 | private AtomicInteger maxSize = new AtomicInteger(DEFAULT_STACK_MAX_SIZE); 46 | 47 | private boolean disabled = true; 48 | // for test 49 | @Getter 50 | private int activeSession = 0; 51 | // for test 52 | @Setter 53 | private boolean unChecked = true; 54 | 55 | private volatile int flushCount = 0; 56 | 57 | private Map flushServices = new HashMap<>(); 58 | 59 | @Setter 60 | @Getter 61 | private LevelDbDataSourceImpl checkpoint; 62 | 63 | @Setter 64 | private volatile int maxFlushCount = DEFAULT_MIN_FLUSH_COUNT; 65 | 66 | public SnapshotManager(String checkpointPath) { 67 | checkpoint = new LevelDbDataSourceImpl( 68 | checkpointPath, "tmp", new Options(), new WriteOptions().sync(false)); 69 | } 70 | 71 | public ISession buildSession() { 72 | return buildSession(false); 73 | } 74 | 75 | public synchronized ISession buildSession(boolean forceEnable) { 76 | if (disabled && !forceEnable) { 77 | return new Session(this); 78 | } 79 | 80 | boolean disableOnExit = disabled && forceEnable; 81 | if (forceEnable) { 82 | disabled = false; 83 | } 84 | 85 | if (size > maxSize.get()) { 86 | flushCount = flushCount + (size - maxSize.get()); 87 | updateSolidity(size - maxSize.get()); 88 | size = maxSize.get(); 89 | flush(); 90 | } 91 | 92 | advance(); 93 | ++activeSession; 94 | return new Session(this, disableOnExit); 95 | } 96 | 97 | @Override 98 | public void setMode(boolean mode) { 99 | dbs.forEach(db -> db.setMode(mode)); 100 | } 101 | 102 | @Override 103 | public void add(IRevokingDB db) { 104 | Chainbase revokingDB = (Chainbase) db; 105 | dbs.add(revokingDB); 106 | flushServices.put(revokingDB.getDbName(), MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())); 107 | } 108 | 109 | private void advance() { 110 | dbs.forEach(db -> db.setHead(db.getHead().advance())); 111 | ++size; 112 | } 113 | 114 | private void retreat() { 115 | dbs.forEach(db -> db.setHead(db.getHead().retreat())); 116 | --size; 117 | } 118 | 119 | public void merge() { 120 | if (activeSession <= 0) { 121 | throw new RevokingStoreIllegalStateException("activeDialog has to be greater than 0"); 122 | } 123 | 124 | if (size < 2) { 125 | return; 126 | } 127 | 128 | dbs.forEach(db -> db.getHead().getPrevious().merge(db.getHead())); 129 | retreat(); 130 | --activeSession; 131 | } 132 | 133 | public synchronized void revoke() { 134 | if (disabled) { 135 | return; 136 | } 137 | 138 | if (activeSession <= 0) { 139 | throw new RevokingStoreIllegalStateException("activeSession has to be greater than 0"); 140 | } 141 | 142 | if (size <= 0) { 143 | return; 144 | } 145 | 146 | disabled = true; 147 | 148 | try { 149 | retreat(); 150 | } finally { 151 | disabled = false; 152 | } 153 | --activeSession; 154 | } 155 | 156 | public synchronized void commit() { 157 | if (activeSession <= 0) { 158 | throw new RevokingStoreIllegalStateException("activeSession has to be greater than 0"); 159 | } 160 | 161 | --activeSession; 162 | } 163 | 164 | public synchronized void pop() { 165 | if (activeSession != 0) { 166 | throw new RevokingStoreIllegalStateException("activeSession has to be equal 0"); 167 | } 168 | 169 | if (size <= 0) { 170 | throw new RevokingStoreIllegalStateException("there is not snapshot to be popped"); 171 | } 172 | 173 | disabled = true; 174 | 175 | try { 176 | retreat(); 177 | } finally { 178 | disabled = false; 179 | } 180 | } 181 | 182 | @Override 183 | public void fastPop() { 184 | pop(); 185 | } 186 | 187 | public synchronized void enable() { 188 | disabled = false; 189 | } 190 | 191 | @Override 192 | public int size() { 193 | return size; 194 | } 195 | 196 | @Override 197 | public void setMaxSize(int maxSize) { 198 | this.maxSize.set(maxSize); 199 | } 200 | 201 | public int getMaxSize() { 202 | return maxSize.get(); 203 | } 204 | 205 | public synchronized void disable() { 206 | disabled = true; 207 | } 208 | 209 | @Override 210 | public void shutdown() { 211 | System.err.println("******** begin to pop revokingDb ********"); 212 | System.err.println("******** before revokingDb size:" + size); 213 | checkpoint.closeDB(); 214 | System.err.println("******** end to pop revokingDb ********"); 215 | } 216 | 217 | public void updateSolidity(int hops) { 218 | for (int i = 0; i < hops; i++) { 219 | for (Chainbase db : dbs) { 220 | db.getHead().updateSolidity(); 221 | } 222 | } 223 | } 224 | 225 | private boolean shouldBeRefreshed() { 226 | return flushCount >= maxFlushCount; 227 | } 228 | 229 | private void refresh() { 230 | List> futures = new ArrayList<>(dbs.size()); 231 | for (Chainbase db : dbs) { 232 | futures.add(flushServices.get(db.getDbName()).submit(() -> refreshOne(db))); 233 | } 234 | Future future = Futures.allAsList(futures); 235 | try { 236 | future.get(); 237 | } catch (InterruptedException e) { 238 | Thread.currentThread().interrupt(); 239 | } catch (ExecutionException e) { 240 | logger.error(e.getMessage(), e); 241 | } 242 | } 243 | 244 | private void refreshOne(Chainbase db) { 245 | if (Snapshot.isRoot(db.getHead())) { 246 | return; 247 | } 248 | 249 | List snapshots = new ArrayList<>(); 250 | 251 | SnapshotRoot root = (SnapshotRoot) db.getHead().getRoot(); 252 | Snapshot next = root; 253 | for (int i = 0; i < flushCount; ++i) { 254 | next = next.getNext(); 255 | snapshots.add(next); 256 | } 257 | 258 | root.merge(snapshots); 259 | 260 | root.resetSolidity(); 261 | if (db.getHead() == next) { 262 | db.setHead(root); 263 | } else { 264 | next.getNext().setPrevious(root); 265 | root.setNext(next.getNext()); 266 | } 267 | } 268 | 269 | public void flush() { 270 | if (unChecked) { 271 | return; 272 | } 273 | 274 | if (shouldBeRefreshed()) { 275 | long start = System.currentTimeMillis(); 276 | deleteCheckpoint(); 277 | createCheckpoint(); 278 | long checkPointEnd = System.currentTimeMillis(); 279 | refresh(); 280 | flushCount = 0; 281 | logger.info("flush cost:{}, create checkpoint cost:{}, refresh cost:{}", 282 | System.currentTimeMillis() - start, 283 | checkPointEnd - start, 284 | System.currentTimeMillis() - checkPointEnd 285 | ); 286 | } 287 | } 288 | 289 | private void createCheckpoint() { 290 | Map batch = new HashMap<>(); 291 | for (Chainbase db : dbs) { 292 | Snapshot head = db.getHead(); 293 | if (Snapshot.isRoot(head)) { 294 | return; 295 | } 296 | 297 | String dbName = db.getDbName(); 298 | Snapshot next = head.getRoot(); 299 | for (int i = 0; i < flushCount; ++i) { 300 | next = next.getNext(); 301 | SnapshotImpl snapshot = (SnapshotImpl) next; 302 | DB keyValueDB = snapshot.getDb(); 303 | for (Map.Entry e : keyValueDB) { 304 | Key k = e.getKey(); 305 | Value v = e.getValue(); 306 | batch.put(WrappedByteArray.of(Bytes.concat(simpleEncode(dbName), k.getBytes())), 307 | WrappedByteArray.of(v.encode())); 308 | } 309 | } 310 | } 311 | 312 | checkpoint.updateByBatch(batch.entrySet().stream() 313 | .map(e -> Maps.immutableEntry(e.getKey().getBytes(), e.getValue().getBytes())) 314 | .collect(HashMap::new, (m, k) -> m.put(k.getKey(), k.getValue()), HashMap::putAll)); 315 | } 316 | 317 | private void deleteCheckpoint() { 318 | Map hmap = new HashMap(); 319 | if (!checkpoint.allKeys().isEmpty()) { 320 | for (Map.Entry e : checkpoint) { 321 | hmap.put(e.getKey(), null); 322 | } 323 | } 324 | 325 | checkpoint.updateByBatch(hmap); 326 | } 327 | 328 | // ensure run this method first after process start. 329 | @Override 330 | public void check() { 331 | for (Chainbase db : dbs) { 332 | if (!Snapshot.isRoot(db.getHead())) { 333 | throw new IllegalStateException("first check."); 334 | } 335 | } 336 | 337 | if (!checkpoint.allKeys().isEmpty()) { 338 | Map dbMap = dbs.stream() 339 | .map(db -> Maps.immutableEntry(db.getDbName(), db)) 340 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 341 | advance(); 342 | for (Map.Entry e : checkpoint) { 343 | byte[] key = e.getKey(); 344 | byte[] value = e.getValue(); 345 | String db = simpleDecode(key); 346 | if (dbMap.get(db) == null) { 347 | continue; 348 | } 349 | byte[] realKey = Arrays.copyOfRange(key, db.getBytes().length + 4, key.length); 350 | 351 | byte[] realValue = value.length == 1 ? null : Arrays.copyOfRange(value, 1, value.length); 352 | if (realValue != null) { 353 | dbMap.get(db).getHead().put(realKey, realValue); 354 | } else { 355 | dbMap.get(db).getHead().remove(realKey); 356 | } 357 | 358 | } 359 | 360 | dbs.forEach(db -> db.getHead().getRoot().merge(db.getHead())); 361 | retreat(); 362 | } 363 | 364 | unChecked = false; 365 | } 366 | 367 | private byte[] simpleEncode(String s) { 368 | byte[] bytes = s.getBytes(); 369 | byte[] length = Ints.toByteArray(bytes.length); 370 | byte[] r = new byte[4 + bytes.length]; 371 | System.arraycopy(length, 0, r, 0, 4); 372 | System.arraycopy(bytes, 0, r, 4, bytes.length); 373 | return r; 374 | } 375 | 376 | public static String simpleDecode(byte[] bytes) { 377 | byte[] lengthBytes = Arrays.copyOf(bytes, 4); 378 | int length = Ints.fromByteArray(lengthBytes); 379 | byte[] value = Arrays.copyOfRange(bytes, 4, 4 + length); 380 | return new String(value); 381 | } 382 | 383 | @Slf4j(topic = "DB") 384 | @Getter // only for unit test 385 | public static class Session implements ISession { 386 | 387 | private SnapshotManager snapshotManager; 388 | private boolean applySnapshot = true; 389 | private boolean disableOnExit = false; 390 | 391 | public Session(SnapshotManager snapshotManager) { 392 | this(snapshotManager, false); 393 | } 394 | 395 | public Session(SnapshotManager snapshotManager, boolean disableOnExit) { 396 | this.snapshotManager = snapshotManager; 397 | this.disableOnExit = disableOnExit; 398 | } 399 | 400 | @Override 401 | public void commit() { 402 | applySnapshot = false; 403 | snapshotManager.commit(); 404 | } 405 | 406 | @Override 407 | public void revoke() { 408 | if (applySnapshot) { 409 | snapshotManager.revoke(); 410 | } 411 | 412 | applySnapshot = false; 413 | } 414 | 415 | @Override 416 | public void merge() { 417 | if (applySnapshot) { 418 | snapshotManager.merge(); 419 | } 420 | 421 | applySnapshot = false; 422 | } 423 | 424 | @Override 425 | public void destroy() { 426 | try { 427 | if (applySnapshot) { 428 | snapshotManager.revoke(); 429 | } 430 | } catch (Exception e) { 431 | logger.error("revoke database error.", e); 432 | } 433 | if (disableOnExit) { 434 | snapshotManager.disable(); 435 | } 436 | } 437 | 438 | @Override 439 | public void close() { 440 | try { 441 | if (applySnapshot) { 442 | snapshotManager.revoke(); 443 | } 444 | } catch (Exception e) { 445 | logger.error("revoke database error.", e); 446 | throw new RevokingStoreIllegalStateException(e); 447 | } 448 | if (disableOnExit) { 449 | snapshotManager.disable(); 450 | } 451 | } 452 | } 453 | 454 | } 455 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/db2/core/SnapshotRoot.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.db2.core; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.collect.Streams; 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.stream.Collectors; 10 | import lombok.Getter; 11 | import org.tron.core.db2.common.DB; 12 | import org.tron.core.db2.common.Flusher; 13 | import org.tron.core.db2.common.WrappedByteArray; 14 | 15 | public class SnapshotRoot extends AbstractSnapshot { 16 | 17 | @Getter 18 | private Snapshot solidity; 19 | 20 | public SnapshotRoot(DB db) { 21 | this.db = db; 22 | solidity = this; 23 | } 24 | 25 | @Override 26 | public byte[] get(byte[] key) { 27 | return db.get(key); 28 | } 29 | 30 | @Override 31 | public void put(byte[] key, byte[] value) { 32 | db.put(key, value); 33 | } 34 | 35 | @Override 36 | public void remove(byte[] key) { 37 | db.remove(key); 38 | } 39 | 40 | @Override 41 | public void merge(Snapshot from) { 42 | SnapshotImpl snapshot = (SnapshotImpl) from; 43 | Map batch = Streams.stream(snapshot.db) 44 | .map(e -> Maps.immutableEntry(WrappedByteArray.of(e.getKey().getBytes()), 45 | WrappedByteArray.of(e.getValue().getBytes()))) 46 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 47 | ((Flusher) db).flush(batch); 48 | } 49 | 50 | public void merge(List snapshots) { 51 | Map batch = new HashMap<>(); 52 | for (Snapshot snapshot : snapshots) { 53 | SnapshotImpl from = (SnapshotImpl) snapshot; 54 | Streams.stream(from.db) 55 | .map(e -> Maps.immutableEntry(WrappedByteArray.of(e.getKey().getBytes()), 56 | WrappedByteArray.of(e.getValue().getBytes()))) 57 | .forEach(e -> batch.put(e.getKey(), e.getValue())); 58 | } 59 | 60 | ((Flusher) db).flush(batch); 61 | } 62 | 63 | @Override 64 | public Snapshot retreat() { 65 | return this; 66 | } 67 | 68 | @Override 69 | public Snapshot getRoot() { 70 | return this; 71 | } 72 | 73 | @Override 74 | public Iterator> iterator() { 75 | return db.iterator(); 76 | } 77 | 78 | @Override 79 | public void close() { 80 | ((Flusher) db).close(); 81 | } 82 | 83 | @Override 84 | public void reset() { 85 | ((Flusher) db).reset(); 86 | } 87 | 88 | @Override 89 | public void resetSolidity() { 90 | solidity = this; 91 | } 92 | 93 | @Override 94 | public void updateSolidity() { 95 | solidity = solidity.getNext(); 96 | } 97 | 98 | @Override 99 | public String getDbName() { 100 | return db.getDbName(); 101 | } 102 | 103 | @Override 104 | public Snapshot newInstance() { 105 | return new SnapshotRoot(db.newInstance()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/exception/ItemNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.exception; 2 | 3 | public class ItemNotFoundException extends StoreException { 4 | 5 | public ItemNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public ItemNotFoundException() { 10 | super(); 11 | } 12 | 13 | public ItemNotFoundException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/exception/RevokingStoreIllegalStateException.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.exception; 2 | 3 | public class RevokingStoreIllegalStateException extends RuntimeException { 4 | 5 | /** 6 | * Constructs an RevokingStoreIllegalStateException with no detail message. A detail message is a 7 | * String that describes this particular exception. 8 | */ 9 | public RevokingStoreIllegalStateException() { 10 | super(); 11 | } 12 | 13 | /** 14 | * Constructs an RevokingStoreIllegalStateException with the specified detail message. A detail 15 | * message is a String that describes this particular exception. 16 | * 17 | * @param s the String that contains a detailed message 18 | */ 19 | public RevokingStoreIllegalStateException(String s) { 20 | super(s); 21 | } 22 | 23 | /** 24 | * Constructs a new exception with the specified detail message and cause. 25 | * 26 | *

Note that the detail message associated with cause is not automatically 27 | * incorporated in this exception's detail message. 28 | * 29 | * @param message the detail message (which is saved for later retrieval by the {@link 30 | * Throwable#getMessage()} method). 31 | * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} 32 | * method). (A null value is permitted, and indicates that the cause is nonexistent or 33 | * unknown.) 34 | */ 35 | public RevokingStoreIllegalStateException(String message, Throwable cause) { 36 | super(message, cause); 37 | } 38 | 39 | /** 40 | * Constructs a new exception with the specified cause and a detail message of (cause==null ? 41 | * null : cause.toString()) (which typically contains the class and detail message of 42 | * cause). This constructor is useful for exceptions that are little more than wrappers 43 | * for other throwables (for example, {@link java.security.PrivilegedActionException}). 44 | * 45 | * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} 46 | * method). (A null value is permitted, and indicates that the cause is nonexistent or 47 | * unknown.) 48 | */ 49 | public RevokingStoreIllegalStateException(Throwable cause) { 50 | super("", cause); 51 | } 52 | 53 | static final long serialVersionUID = -1848914673093119416L; 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/tron/core/exception/StoreException.java: -------------------------------------------------------------------------------- 1 | package org.tron.core.exception; 2 | 3 | public class StoreException extends Exception { 4 | 5 | public StoreException() { 6 | super(); 7 | } 8 | 9 | public StoreException(String message) { 10 | super(message); 11 | } 12 | 13 | public StoreException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | 17 | public StoreException(Throwable cause) { 18 | super(cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/tron/utils/ByteUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) [2016] [ ] 3 | * This file is part of the ethereumJ library. 4 | * 5 | * The ethereumJ library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The ethereumJ library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with the ethereumJ library. If not, see . 17 | */ 18 | 19 | package org.tron.utils; 20 | 21 | import com.google.common.base.Preconditions; 22 | import com.google.common.primitives.UnsignedBytes; 23 | import java.math.BigInteger; 24 | import java.nio.ByteBuffer; 25 | import java.util.Arrays; 26 | 27 | public class ByteUtil { 28 | 29 | public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; 30 | public static final byte[] ZERO_BYTE_ARRAY = new byte[]{0}; 31 | 32 | 33 | /** 34 | * return a cloned byte array. 35 | * return null if parameter data is null 36 | * @param data 37 | * @return 38 | */ 39 | public static byte[] cloneBytes(byte[] data){ 40 | if (data == null){ 41 | return null; 42 | } 43 | 44 | int length = data.length; 45 | byte[] rc = new byte[length]; 46 | if (length > 0){ 47 | System.arraycopy(data, 0, rc, 0, length); 48 | } 49 | return rc; 50 | } 51 | 52 | /** 53 | * The regular {@link BigInteger#toByteArray()} method isn't quite what we often need: 54 | * it appends a leading zero to indicate that the number is positive and may need padding. 55 | * 56 | * @param b the integer to format into a byte array 57 | * @param numBytes the desired size of the resulting byte array 58 | * @return numBytes byte long array. 59 | */ 60 | public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) { 61 | if (b == null) { 62 | return null; 63 | } 64 | byte[] bytes = new byte[numBytes]; 65 | byte[] biBytes = b.toByteArray(); 66 | int start = (biBytes.length == numBytes + 1) ? 1 : 0; 67 | int length = Math.min(biBytes.length, numBytes); 68 | System.arraycopy(biBytes, start, bytes, numBytes - length, length); 69 | return bytes; 70 | } 71 | 72 | public static byte[] bigIntegerToBytes(BigInteger value) { 73 | if (value == null) { 74 | return null; 75 | } 76 | 77 | byte[] data = value.toByteArray(); 78 | 79 | if (data.length != 1 && data[0] == 0) { 80 | byte[] tmp = new byte[data.length - 1]; 81 | System.arraycopy(data, 1, tmp, 0, tmp.length); 82 | data = tmp; 83 | } 84 | return data; 85 | } 86 | 87 | /** 88 | * merge arrays. 89 | * 90 | * @param arrays - arrays to merge 91 | * @return - merged array 92 | */ 93 | public static byte[] merge(byte[]... arrays) { 94 | int count = 0; 95 | for (byte[] array : arrays) { 96 | count += array.length; 97 | } 98 | 99 | // Create new array and copy all array contents 100 | byte[] mergedArray = new byte[count]; 101 | int start = 0; 102 | for (byte[] array : arrays) { 103 | System.arraycopy(array, 0, mergedArray, start, array.length); 104 | start += array.length; 105 | } 106 | return mergedArray; 107 | } 108 | 109 | /** 110 | * Creates a copy of bytes and appends b to the end of it. 111 | */ 112 | public static byte[] appendByte(byte[] bytes, byte b) { 113 | byte[] result = Arrays.copyOf(bytes, bytes.length + 1); 114 | result[result.length - 1] = b; 115 | return result; 116 | } 117 | 118 | /** 119 | * Turn nibbles to a pretty looking output string Example. [ 1, 2, 3, 4, 5 ] becomes 120 | * '\x11\x23\x45' 121 | * 122 | * @param nibbles - getting byte of data [ 04 ] and turning it to a '\x04' representation 123 | * @return pretty string of nibbles 124 | */ 125 | public static String nibblesToPrettyString(byte[] nibbles) { 126 | StringBuilder builder = new StringBuilder(); 127 | for (byte nibble : nibbles) { 128 | final String nibbleString = oneByteToHexString(nibble); 129 | builder.append("\\x").append(nibbleString); 130 | } 131 | return builder.toString(); 132 | } 133 | 134 | /** 135 | * get hex string data from byte data. 136 | */ 137 | public static String oneByteToHexString(byte value) { 138 | String retVal = Integer.toString(value & 0xFF, 16); 139 | if (retVal.length() == 1) { 140 | retVal = "0" + retVal; 141 | } 142 | return retVal; 143 | } 144 | 145 | /** 146 | * Cast hex encoded value from byte[] to int Limited to Integer.MAX_VALUE: 2^32-1 (4 bytes) 147 | * 148 | * @param b array contains the values 149 | * @return unsigned positive int value. 150 | */ 151 | public static int byteArrayToInt(byte[] b) { 152 | if (b == null || b.length == 0) { 153 | return 0; 154 | } 155 | return new BigInteger(1, b).intValue(); 156 | } 157 | 158 | public static boolean isSingleZero(byte[] array) { 159 | return (array.length == 1 && array[0] == 0); 160 | } 161 | 162 | /** 163 | * Converts a int value into a byte array. 164 | * 165 | * @param val - int value to convert 166 | * @return value with leading byte that are zeroes striped 167 | */ 168 | public static byte[] intToBytesNoLeadZeroes(int val) { 169 | 170 | if (val == 0) { 171 | return EMPTY_BYTE_ARRAY; 172 | } 173 | 174 | int lenght = 0; 175 | 176 | int tmpVal = val; 177 | while (tmpVal != 0) { 178 | tmpVal = tmpVal >>> 8; 179 | ++lenght; 180 | } 181 | 182 | byte[] result = new byte[lenght]; 183 | 184 | int index = result.length - 1; 185 | while (val != 0) { 186 | 187 | result[index] = (byte) (val & 0xFF); 188 | val = val >>> 8; 189 | index -= 1; 190 | } 191 | 192 | return result; 193 | } 194 | 195 | /** 196 | * Converts int value into a byte array. 197 | * 198 | * @param val - int value to convert 199 | * @return byte[] of length 4, representing the int value 200 | */ 201 | public static byte[] intToBytes(int val) { 202 | return ByteBuffer.allocate(4).putInt(val).array(); 203 | } 204 | 205 | /** 206 | * Cast hex encoded value from byte[] to BigInteger null is parsed like byte[0] 207 | * 208 | * @param bb byte array contains the values 209 | * @return unsigned positive BigInteger value. 210 | */ 211 | public static BigInteger bytesToBigInteger(byte[] bb) { 212 | return (bb == null || bb.length == 0) ? BigInteger.ZERO : new BigInteger(1, bb); 213 | } 214 | 215 | /** 216 | * Cast hex encoded value from byte[] to long null is parsed like byte[0] 217 | * 218 | * Limited to Long.MAX_VALUE: 263-1 (8 bytes) 219 | * 220 | * @param b array contains the values 221 | * @return unsigned positive long value. 222 | */ 223 | public static long byteArrayToLong(byte[] b) { 224 | if (b == null || b.length == 0) { 225 | return 0; 226 | } 227 | return new BigInteger(1, b).longValueExact(); 228 | } 229 | 230 | public static int firstNonZeroByte(byte[] data) { 231 | for (int i = 0; i < data.length; ++i) { 232 | if (data[i] != 0) { 233 | return i; 234 | } 235 | } 236 | return -1; 237 | } 238 | 239 | public static byte[] stripLeadingZeroes(byte[] data) { 240 | 241 | if (data == null) { 242 | return null; 243 | } 244 | 245 | final int firstNonZero = firstNonZeroByte(data); 246 | switch (firstNonZero) { 247 | case -1: 248 | return ZERO_BYTE_ARRAY; 249 | 250 | case 0: 251 | return data; 252 | 253 | default: 254 | byte[] result = new byte[data.length - firstNonZero]; 255 | System.arraycopy(data, firstNonZero, result, 0, data.length - firstNonZero); 256 | 257 | return result; 258 | } 259 | } 260 | 261 | /** 262 | * Utility function to copy a byte array into a new byte array with given size. If the src length 263 | * is smaller than the given size, the result will be left-padded with zeros. 264 | * 265 | * @param value - a BigInteger with a maximum value of 2^256-1 266 | * @return Byte array of given size with a copy of the src 267 | */ 268 | public static byte[] copyToArray(BigInteger value) { 269 | byte[] dest = ByteBuffer.allocate(32).array(); 270 | byte[] src = ByteUtil.bigIntegerToBytes(value); 271 | if (src != null) { 272 | System.arraycopy(src, 0, dest, dest.length - src.length, src.length); 273 | } 274 | return dest; 275 | } 276 | 277 | /** 278 | * Returns a number of zero bits preceding the highest-order ("leftmost") one-bit interpreting 279 | * input array as a big-endian integer value 280 | */ 281 | public static int numberOfLeadingZeros(byte[] bytes) { 282 | 283 | int i = firstNonZeroByte(bytes); 284 | 285 | if (i == -1) { 286 | return bytes.length * 8; 287 | } else { 288 | int byteLeadingZeros = Integer.numberOfLeadingZeros((int) bytes[i] & 0xff) - 24; 289 | return i * 8 + byteLeadingZeros; 290 | } 291 | } 292 | 293 | /** 294 | * Parses fixed number of bytes starting from {@code offset} in {@code input} array. If {@code 295 | * input} has not enough bytes return array will be right padded with zero bytes. I.e. if {@code 296 | * offset} is higher than {@code input.length} then zero byte array of length {@code len} will be 297 | * returned 298 | */ 299 | public static byte[] parseBytes(byte[] input, int offset, int len) { 300 | 301 | if (offset >= input.length || len == 0) { 302 | return EMPTY_BYTE_ARRAY; 303 | } 304 | 305 | byte[] bytes = new byte[len]; 306 | System.arraycopy(input, offset, bytes, 0, Math.min(input.length - offset, len)); 307 | return bytes; 308 | } 309 | 310 | /** 311 | * Parses 32-bytes word from given input. Uses {@link #parseBytes(byte[], int, int)} method, thus, 312 | * result will be right-padded with zero bytes if there is not enough bytes in {@code input} 313 | * 314 | * @param idx an index of the word starting from {@code 0} 315 | */ 316 | public static byte[] parseWord(byte[] input, int idx) { 317 | return parseBytes(input, 32 * idx, 32); 318 | } 319 | 320 | /** 321 | * Parses 32-bytes word from given input. Uses {@link #parseBytes(byte[], int, int)} method, thus, 322 | * result will be right-padded with zero bytes if there is not enough bytes in {@code input} 323 | * 324 | * @param idx an index of the word starting from {@code 0} 325 | * @param offset an offset in {@code input} array to start parsing from 326 | */ 327 | public static byte[] parseWord(byte[] input, int offset, int idx) { 328 | return parseBytes(input, offset + 32 * idx, 32); 329 | } 330 | 331 | public static boolean greater(byte[] bytes1, byte[] bytes2) { 332 | return compare(bytes1, bytes2) > 0; 333 | } 334 | 335 | public static boolean greaterOrEquals(byte[] bytes1, byte[] bytes2) { 336 | return compare(bytes1, bytes2) >= 0; 337 | } 338 | 339 | public static boolean less(byte[] bytes1, byte[] bytes2) { 340 | return compare(bytes1, bytes2) < 0; 341 | } 342 | 343 | public static boolean lessOrEquals(byte[] bytes1, byte[] bytes2) { 344 | return compare(bytes1, bytes2) <= 0; 345 | } 346 | 347 | public static boolean equals(byte[] bytes1, byte[] bytes2) { 348 | return compare(bytes1, bytes2) == 0; 349 | } 350 | 351 | // lexicographical order 352 | public static int compare(byte[] bytes1, byte[] bytes2) { 353 | Preconditions.checkNotNull(bytes1); 354 | Preconditions.checkNotNull(bytes2); 355 | Preconditions.checkArgument(bytes1.length == bytes2.length); 356 | int length = bytes1.length; 357 | for (int i = 0; i < length; ++i) { 358 | int ret = UnsignedBytes.compare(bytes1[i], bytes2[i]); 359 | if (ret != 0) { 360 | return ret; 361 | } 362 | } 363 | 364 | return 0; 365 | } 366 | 367 | } -------------------------------------------------------------------------------- /src/main/java/org/tron/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) [2016] [ ] This file is part of the ethereumJ library. 3 | * 4 | * The ethereumJ library is free software: you can redistribute it and/or modify it under the terms 5 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either 6 | * version 3 of the License, or (at your option) any later version. 7 | * 8 | * The ethereumJ library is distributed in the hope that it will be useful, but WITHOUT ANY 9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 10 | * PURPOSE. See the GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License along with the ethereumJ 13 | * library. If not, see . 14 | */ 15 | 16 | package org.tron.utils; 17 | 18 | import java.io.BufferedReader; 19 | import java.io.BufferedWriter; 20 | import java.io.File; 21 | import java.io.FileReader; 22 | import java.io.FileWriter; 23 | import java.io.IOException; 24 | import java.nio.file.FileVisitResult; 25 | import java.nio.file.FileVisitor; 26 | import java.nio.file.Files; 27 | import java.nio.file.Path; 28 | import java.nio.file.Paths; 29 | import java.nio.file.attribute.BasicFileAttributes; 30 | import java.util.ArrayList; 31 | import java.util.Arrays; 32 | import java.util.List; 33 | import java.util.Objects; 34 | import lombok.extern.slf4j.Slf4j; 35 | 36 | @Slf4j(topic = "utils") 37 | public class FileUtil { 38 | 39 | public static List recursiveList(String path) throws IOException { 40 | 41 | final List files = new ArrayList<>(); 42 | 43 | Files.walkFileTree(Paths.get(path), new FileVisitor() { 44 | @Override 45 | public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { 46 | return FileVisitResult.CONTINUE; 47 | } 48 | 49 | @Override 50 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 51 | files.add(file.toString()); 52 | return FileVisitResult.CONTINUE; 53 | } 54 | 55 | @Override 56 | public FileVisitResult visitFileFailed(Path file, IOException exc) { 57 | return FileVisitResult.CONTINUE; 58 | } 59 | 60 | @Override 61 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) { 62 | return FileVisitResult.CONTINUE; 63 | } 64 | }); 65 | 66 | return files; 67 | } 68 | 69 | public static boolean recursiveDelete(String fileName) { 70 | File file = new File(fileName); 71 | if (file.exists()) { 72 | // check if the file is a directory 73 | if (file.isDirectory()) { 74 | // call deletion of file individually 75 | Arrays.stream(Objects.requireNonNull(file.list())) 76 | .map(s -> fileName + System.getProperty("file.separator") + s) 77 | .forEachOrdered(FileUtil::recursiveDelete); 78 | } 79 | 80 | file.setWritable(true); 81 | return file.delete(); 82 | } 83 | return false; 84 | } 85 | 86 | public static void saveData(String filePath, String data, boolean append) { 87 | File priFile = new File(filePath); 88 | try { 89 | priFile.createNewFile(); 90 | try (BufferedWriter bw = new BufferedWriter(new FileWriter(priFile, append))) { 91 | bw.write(data); 92 | bw.flush(); 93 | } 94 | } catch (IOException e) { 95 | logger.debug(e.getMessage(), e); 96 | } 97 | } 98 | 99 | public static int readData(String filePath, char[] buf) { 100 | int len; 101 | File file = new File(filePath); 102 | try (BufferedReader bufRead = new BufferedReader(new FileReader(file))) { 103 | len = bufRead.read(buf, 0, buf.length); 104 | } catch (IOException ex) { 105 | ex.printStackTrace(); 106 | return 0; 107 | } 108 | return len; 109 | } 110 | 111 | /** 112 | * delete directory. 113 | */ 114 | public static boolean deleteDir(File dir) { 115 | if (dir.isDirectory()) { 116 | String[] children = dir.list(); 117 | for (int i = 0; i < children.length; i++) { 118 | boolean success = deleteDir(new File(dir, children[i])); 119 | if (!success) { 120 | logger.warn("can't delete dir:" + dir); 121 | return false; 122 | } 123 | } 124 | } 125 | return dir.delete(); 126 | } 127 | } 128 | --------------------------------------------------------------------------------