├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── bintray.gradle ├── install.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── leveldb ├── .gitignore ├── build.gradle ├── gradle.properties ├── notice.md └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ ├── com │ │ └── simsun │ │ │ └── common │ │ │ └── base │ │ │ ├── MultiMap.java │ │ │ ├── PeekingIterator.java │ │ │ ├── PeekingIteratorImpl.java │ │ │ ├── Preconditions.java │ │ │ ├── StandardCharsets.java │ │ │ ├── ThreadFactoryBuilder.java │ │ │ └── Utils.java │ │ └── org │ │ └── iq80 │ │ └── leveldb │ │ ├── CompressionType.java │ │ ├── DB.java │ │ ├── DBComparator.java │ │ ├── DBException.java │ │ ├── DBFactory.java │ │ ├── DBIterator.java │ │ ├── Logger.java │ │ ├── Options.java │ │ ├── Range.java │ │ ├── ReadOptions.java │ │ ├── Snapshot.java │ │ ├── WriteBatch.java │ │ ├── WriteOptions.java │ │ ├── impl │ │ ├── Compaction.java │ │ ├── DbConstants.java │ │ ├── DbImpl.java │ │ ├── DbLock.java │ │ ├── FileChannelLogWriter.java │ │ ├── FileMetaData.java │ │ ├── Filename.java │ │ ├── InternalEntry.java │ │ ├── InternalKey.java │ │ ├── InternalKeyComparator.java │ │ ├── InternalUserComparator.java │ │ ├── Iq80DBFactory.java │ │ ├── Level.java │ │ ├── Level0.java │ │ ├── LogChunkType.java │ │ ├── LogConstants.java │ │ ├── LogMonitor.java │ │ ├── LogMonitors.java │ │ ├── LogReader.java │ │ ├── LogWriter.java │ │ ├── Logs.java │ │ ├── LookupKey.java │ │ ├── LookupResult.java │ │ ├── MMapLogWriter.java │ │ ├── MemTable.java │ │ ├── ReadStats.java │ │ ├── SeekingIterable.java │ │ ├── SeekingIterator.java │ │ ├── SeekingIteratorAdapter.java │ │ ├── SequenceNumber.java │ │ ├── SnapshotImpl.java │ │ ├── SnapshotSeekingIterator.java │ │ ├── TableCache.java │ │ ├── ValueType.java │ │ ├── Version.java │ │ ├── VersionEdit.java │ │ ├── VersionEditTag.java │ │ ├── VersionSet.java │ │ └── WriteBatchImpl.java │ │ ├── table │ │ ├── Block.java │ │ ├── BlockBuilder.java │ │ ├── BlockEntry.java │ │ ├── BlockHandle.java │ │ ├── BlockIterator.java │ │ ├── BlockTrailer.java │ │ ├── BytewiseComparator.java │ │ ├── CustomUserComparator.java │ │ ├── FileChannelTable.java │ │ ├── Footer.java │ │ ├── MMapTable.java │ │ ├── Table.java │ │ ├── TableBuilder.java │ │ └── UserComparator.java │ │ └── util │ │ ├── AbstractSeekingIterator.java │ │ ├── BasicSliceOutput.java │ │ ├── ByteBufferSupport.java │ │ ├── Closeables.java │ │ ├── DbIterator.java │ │ ├── DynamicSliceOutput.java │ │ ├── FileUtils.java │ │ ├── Finalizer.java │ │ ├── IntVector.java │ │ ├── InternalIterator.java │ │ ├── InternalTableIterator.java │ │ ├── Level0Iterator.java │ │ ├── LevelIterator.java │ │ ├── MergingIterator.java │ │ ├── PureJavaCrc32C.java │ │ ├── SizeOf.java │ │ ├── Slice.java │ │ ├── SliceComparator.java │ │ ├── SliceInput.java │ │ ├── SliceOutput.java │ │ ├── Slices.java │ │ ├── Snappy.java │ │ ├── TableIterator.java │ │ └── VariableLengthQuantity.java │ └── test │ └── java │ └── org │ └── iq80 │ └── leveldb │ ├── impl │ ├── ApiTest.java │ ├── DbImplTest.java │ ├── LogTest.java │ ├── NativeInteropTest.java │ ├── TestFileChannelLogWriter.java │ └── TestMMapLogWriter.java │ ├── table │ ├── BlockHelper.java │ ├── BlockTest.java │ ├── FileChannelTableTest.java │ ├── MMapTableTest.java │ └── TableTest.java │ └── util │ ├── PureJavaCrc32CTest.java │ ├── SliceComparatorTest.java │ └── VariableLengthQuantityTest.java ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── simsun │ │ └── yasp │ │ └── samples │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── simsun │ │ │ └── yasp │ │ │ └── samples │ │ │ ├── BenchmarkActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MultipleThreadActivity.java │ │ │ └── SingleThreadActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_benchmark.xml │ │ ├── activity_main.xml │ │ ├── activity_mutiple_thread.xml │ │ ├── activity_single_thread.xml │ │ └── content_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── simsun │ └── yasp │ └── samples │ └── ExampleUnitTest.java ├── settings.gradle └── yasp-leveldb ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── simsun │ └── yasp │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml └── java │ └── com │ └── simsun │ └── yasp │ ├── ParcelableUtil.java │ ├── YASPContext.java │ └── YASharedPreferences.java └── test └── java └── com └── simsun └── yasp └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | .idea 57 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | script: "./gradlew clean install check" 3 | before_install: 4 | - yes | sdkmanager "platforms;android-27" 5 | android: 6 | components: 7 | - tools 8 | - platform-tools 9 | - tools 10 | # The BuildTools version used by your project 11 | - build-tools-27.0.3 12 | # The SDK version used to compile your project 13 | - android-27 14 | licenses: 15 | - android-sdk-preview-license-.+ 16 | - android-sdk-license-.+ 17 | before_cache: 18 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 19 | cache: 20 | directories: 21 | - $HOME/.m2 22 | - $HOME/.gradle/caches/ 23 | - $HOME/.gradle/wrapper/ 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yet Another SharedPreference 2 | [ ![Download](https://api.bintray.com/packages/simsun/maven/yasp-leveldb/images/download.svg) ](https://bintray.com/simsun/maven/yasp-leveldb/_latestVersion) 3 | [![Build Status](https://travis-ci.org/simpleton/Yasp.svg?branch=master)](https://travis-ci.org/simpleton/Yasp) 4 | 5 | This library try to introduce a high performance K-V store in Android development to instead of [SharedPreference](https://developer.android.com/reference/android/content/SharedPreferences.html). 6 | 7 | ## Why 8 | If you only need to persist simple values and your application runs in a single process SharedPreferences is probably enough for you. It is a good default option. 9 | 10 | There are some situations where SharedPreferences are not suitable for store KV data: 11 | 12 | 1. Performance: Your data is complex or there is a lot of it 13 | 2. Multiple thread accessing the data: invoke `editor.appy()` or `editor.commit()` multiple time, even [`apply`](http://aosp.opersys.com/xref/android-8.1.0_r18/xref/frameworks/base/core/java/android/app/SharedPreferencesImpl.java#410) will submit work to other thread. 14 | 3. Multiple processes accessing the data: You have widgets or remote services that run in their own processes and require synchronized data 15 | 16 | ## Yasp-leveldb 17 | This library is wrapped [LevelDB in java](https://github.com/dain/leveldb) with [SharedPreference](https://developer.android.com/reference/android/content/SharedPreferences.html) interface. 18 | 19 | ### Download 20 | **Use Gradle:** 21 | ```gradle 22 | implementation 'com.simsun.yasp:yasp-leveldb:0.0.3' 23 | ``` 24 | 25 | ### API Usage 26 | Almost compat with Android [SharedPreference](https://developer.android.com/reference/android/content/SharedPreferences.html), but there is a little different during initializing. 27 | 28 | Yasp will **NOT** load whole file when you access one parameter. Feel free to cache yasp instance in your Application. 29 | 30 | #### Init 31 | ```java 32 | SharedPreferences sp = YASPContext.with(Context ct).getSharedPreferences(String name, int mode); 33 | ``` 34 | **Do NOT support multiple processes currently** 35 | 36 | #### Get 37 | As same as Android [SharedPreference](https://developer.android.com/reference/android/content/SharedPreferences.html) 38 | ```java 39 | sp.getString(String key, String defaultVal); 40 | ``` 41 | 42 | #### Editor 43 | As same as Android [SharedPreference](https://developer.android.com/reference/android/content/SharedPreferences.html) 44 | ```java 45 | sp.edit() 46 | .putString(String key, String value) 47 | .putInt(String key, int value) 48 | .apply(); 49 | ``` 50 | 51 | ## Benchmark 52 | // TODO 53 | 54 | ## Reference 55 | 1. [Best practices in Android development](https://github.com/futurice/android-best-practices#data-storage) 56 | 2. [请不要滥用SharedPreference](http://weishu.me/2016/10/13/sharedpreference-advices/) -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.1' 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | classpath 'com.ofg:uptodate-gradle-plugin:1.6.3' 14 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0' 15 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | //mavenLocal() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | 31 | project.ext { 32 | BuildToolsVersion = "27.0.3" 33 | TargetSdkVersion = 27 34 | MinSdkVersion = 15 35 | CompileSdkVersion = 27 36 | AndroidSupportVersion = "27.1.1" 37 | JunitVersion = "4.12" 38 | } 39 | 40 | ext { 41 | bintrayRepo = 'maven' 42 | publishedGroupId = POM_GROUP 43 | libraryDescription = POM_DESCRIPTION 44 | siteUrl = POM_URL 45 | gitUrl = POM_GIT_URL 46 | libraryVersion = POM_VERSION_NAME 47 | developerId = POM_DEVELOPER_ID 48 | developerName = POM_DEVELOPER_NAME 49 | developerEmail = POM_DEVELOPER_EMAIL 50 | 51 | licenseName = 'Apache License 2.0' 52 | licenseUrl = 'https://opensource.org/licenses/Apache-2.0' 53 | allLicenses = ["Apache-2.0"] 54 | } 55 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | POM_VERSION_NAME=0.0.3 16 | 17 | POM_GROUP=com.simsun.yasp 18 | POM_DESCRIPTION=Yet Another Shared Preference 19 | POM_URL=https://github.com/simpleton/Yasp 20 | POM_GIT_URL=https://github.com/simpleton/Yasp.git 21 | POM_DEVELOPER_ID=simsun 22 | POM_DEVELOPER_NAME=Shengjie Sun 23 | POM_DEVELOPER_EMAIL=sunsj1231@gmail.com -------------------------------------------------------------------------------- /gradle/bintray.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.jfrog.bintray' 2 | apply plugin: 'maven-publish' 3 | 4 | version = libraryVersion 5 | project.archivesBaseName = ext.artifact 6 | 7 | def isAndroidProject = project.plugins.hasPlugin('com.android.application') || project.plugins. 8 | hasPlugin('com.android.library') 9 | if (isAndroidProject) { 10 | def releaseVariants = project.android.libraryVariants.findAll { 11 | it.buildType.name.equalsIgnoreCase('release') 12 | } 13 | 14 | task androidJavadocs(type: Javadoc, dependsOn: 'compileReleaseJavaWithJavac') { 15 | source = releaseVariants.collect { it.javaCompile.source } 16 | classpath = files(releaseVariants.collect { 17 | files(it.javaCompile.classpath.files, project.android.bootClasspath) 18 | }) 19 | 20 | options { 21 | encoding "UTF-8" 22 | charSet 'UTF-8' 23 | title "$libraryName $libraryVersion" 24 | author true 25 | version true 26 | links('http://docs.oracle.com/javase/7/docs/api/') 27 | linksOffline('http://d.android.com/reference', "${android.sdkDirectory}/docs/reference") 28 | } 29 | 30 | exclude '**/BuildConfig.java' 31 | exclude '**/R.java' 32 | } 33 | 34 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 35 | classifier = 'javadoc' 36 | from androidJavadocs.destinationDir 37 | baseName "${project.name}${JAR_POSTFIX}" 38 | } 39 | 40 | task androidSourcesJar(type: Jar) { 41 | classifier = 'sources' 42 | from project.android.sourceSets.main.java.source 43 | exclude '**/loader/**' 44 | exclude '**/tinker/**' 45 | exclude '**/server/**' 46 | exclude '**/util/**' 47 | baseName "${project.name}${JAR_POSTFIX}" 48 | } 49 | 50 | artifacts { 51 | archives androidSourcesJar 52 | archives androidJavadocsJar 53 | } 54 | 55 | publishing { 56 | publications { 57 | TinkerServer(MavenPublication) { 58 | groupId = group 59 | artifactId = project.getName() 60 | version = version 61 | // Tell maven to prepare the generated "*.aar" file for publishing 62 | artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") 63 | artifact androidJavadocsJar 64 | } 65 | } 66 | } 67 | } else if (project.plugins.hasPlugin('java')) { 68 | // Java libraries 69 | println "[bintray.gradle]java project" 70 | task sourcesJar(type: Jar, dependsOn: classes) { 71 | classifier = 'sources' 72 | from sourceSets.main.allSource 73 | exclude '**/extension/**' 74 | exclude '**/task/**' 75 | exclude '**/utils/**' 76 | } 77 | task javadocsJar(type: Jar, dependsOn: javadoc) { 78 | classifier = 'javadoc' 79 | from javadoc.destinationDir 80 | } 81 | 82 | artifacts { 83 | archives sourcesJar 84 | archives javadocsJar 85 | } 86 | 87 | publishing { 88 | publications { 89 | TinkerServer(MavenPublication) { 90 | from components.java 91 | groupId = group 92 | artifactId = project.getName() 93 | version = version 94 | } 95 | } 96 | } 97 | } 98 | 99 | task buildAndPublishLocalMaven(dependsOn: ['build', 'publishTinkerServerPublicationToMavenLocal']) { 100 | } 101 | 102 | logger.info("Published artifacts in ${configurations.archives}:") 103 | configurations.archives.artifacts.files.files.each { logger.info("\t$it"); } 104 | 105 | Properties properties = new Properties() 106 | try { 107 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 108 | } catch (ignored) { 109 | properties.setProperty("bintray.user", "user") 110 | properties.setProperty("bintray.apikey", "key") 111 | properties.setProperty("bintray.gpg.password", "pwd") 112 | } 113 | 114 | bintray { 115 | user = properties.getProperty("bintray.user") 116 | key = properties.getProperty("bintray.apikey") 117 | 118 | configurations = ['archives'] 119 | 120 | pkg { 121 | repo = bintrayRepo 122 | name = bintrayName 123 | desc = libraryDescription 124 | websiteUrl = siteUrl 125 | vcsUrl = gitUrl 126 | licenses = allLicenses 127 | publish = true 128 | dryRun = false 129 | publicDownloadNumbers = true 130 | version { 131 | desc = libraryDescription 132 | // gpg { 133 | // sign = false //Determines whether to GPG sign the files. The default is false 134 | // passphrase = properties.getProperty("bintray.gpg.password") 135 | // //Optional. The passphrase for GPG signing' 136 | // } 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /gradle/install.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | 3 | group = publishedGroupId // Maven Group ID for the artifact 4 | project.archivesBaseName = ext.artifact 5 | 6 | install { 7 | repositories.mavenInstaller { 8 | // This generates POM.xml with proper parameters 9 | pom.project { 10 | packaging packageMethod 11 | groupId publishedGroupId 12 | artifactId artifact 13 | 14 | // Add your description here 15 | name libraryName 16 | description libraryDescription 17 | url siteUrl 18 | 19 | // Set your license 20 | licenses { 21 | license { 22 | name licenseName 23 | url licenseUrl 24 | } 25 | } 26 | developers { 27 | developer { 28 | id developerId 29 | name developerName 30 | email developerEmail 31 | } 32 | } 33 | scm { 34 | connection gitUrl 35 | developerConnection gitUrl 36 | url siteUrl 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simpleton/Yasp/cbd539e01607323dd9bd44cdacdb533255b39884/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Apr 01 02:29:52 PDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /leveldb/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /leveldb/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | ext { 4 | bintrayName = POM_NAME 5 | libraryName = POM_NAME 6 | artifact = POM_ARTIFACT_ID 7 | packageMethod = POM_PACKAGING 8 | } 9 | 10 | android { 11 | compileSdkVersion project.CompileSdkVersion 12 | buildToolsVersion project.BuildToolsVersion 13 | 14 | defaultConfig { 15 | minSdkVersion project.MinSdkVersion 16 | targetSdkVersion project.TargetSdkVersion 17 | versionCode 1 18 | versionName "1.0" 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | 32 | implementation "com.android.support:appcompat-v7:${project.AndroidSupportVersion}" 33 | 34 | testImplementation "org.testng:testng:6.14.2" 35 | testImplementation "junit:junit:${project.JunitVersion}" 36 | } 37 | 38 | apply from: "${rootProject.projectDir}/gradle/install.gradle" 39 | apply from: "${rootProject.projectDir}/gradle/bintray.gradle" -------------------------------------------------------------------------------- /leveldb/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=leveldb 2 | POM_NAME=leveldb 3 | POM_PACKAGING=jar 4 | # Postfix for source and javadoc jars. 5 | JAR_POSTFIX= -------------------------------------------------------------------------------- /leveldb/notice.md: -------------------------------------------------------------------------------- 1 | LevelDB Copyright Notices 2 | ========================= 3 | 4 | * Copyright 2011 Dain Sundstrom 5 | * Copyright 2011 FuseSource Corp. http://fusesource.com -------------------------------------------------------------------------------- /leveldb/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /leveldb/src/main/java/com/simsun/common/base/PeekingIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Guava Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.simsun.common.base; 18 | 19 | import java.util.Iterator; 20 | import java.util.NoSuchElementException; 21 | 22 | /** 23 | * An iterator that supports a one-element lookahead while iterating. 24 | * 25 | *

See the Guava User Guide article on {@code 27 | * PeekingIterator}. 28 | * 29 | * @author Mick Killianey 30 | * @since 2.0 31 | */ 32 | public interface PeekingIterator extends Iterator { 33 | /** 34 | * Returns the next element in the iteration, without advancing the iteration. 35 | * 36 | *

Calls to {@code peek()} should not change the state of the iteration, except that it 37 | * may prevent removal of the most recent element via {@link #remove()}. 38 | * 39 | * @throws NoSuchElementException if the iteration has no more elements according to {@link 40 | * #hasNext()} 41 | */ 42 | E peek(); 43 | 44 | /** 45 | * {@inheritDoc} 46 | * 47 | *

The objects returned by consecutive calls to {@link #peek()} then {@link #next()} are 48 | * guaranteed to be equal to each other. 49 | */ 50 | @Override 51 | E next(); 52 | 53 | /** 54 | * {@inheritDoc} 55 | * 56 | *

Implementations may or may not support removal when a call to {@link #peek()} has occurred 57 | * since the most recent call to {@link #next()}. 58 | * 59 | * @throws IllegalStateException if there has been a call to {@link #peek()} since the most recent 60 | * call to {@link #next()} and this implementation does not support this sequence of calls 61 | * (optional) 62 | */ 63 | @Override 64 | void remove(); 65 | } -------------------------------------------------------------------------------- /leveldb/src/main/java/com/simsun/common/base/PeekingIteratorImpl.java: -------------------------------------------------------------------------------- 1 | package com.simsun.common.base; 2 | 3 | import android.support.annotation.Nullable; 4 | import java.util.Iterator; 5 | 6 | import static com.simsun.common.base.Preconditions.checkNotNull; 7 | import static com.simsun.common.base.Preconditions.checkState; 8 | 9 | /** 10 | * Implementation of PeekingIterator that avoids peeking unless necessary. 11 | */ 12 | public class PeekingIteratorImpl implements PeekingIterator { 13 | 14 | private final Iterator iterator; 15 | private boolean hasPeeked; 16 | @Nullable private E peekedElement; 17 | 18 | public PeekingIteratorImpl(Iterator iterator) { 19 | this.iterator = checkNotNull(iterator); 20 | } 21 | 22 | @Override 23 | public boolean hasNext() { 24 | return hasPeeked || iterator.hasNext(); 25 | } 26 | 27 | @Override 28 | public E next() { 29 | if (!hasPeeked) { 30 | return iterator.next(); 31 | } 32 | E result = peekedElement; 33 | hasPeeked = false; 34 | peekedElement = null; 35 | return result; 36 | } 37 | 38 | @Override 39 | public void remove() { 40 | checkState(!hasPeeked, "Can't remove after you've peeked at next"); 41 | iterator.remove(); 42 | } 43 | 44 | @Override 45 | public E peek() { 46 | if (!hasPeeked) { 47 | peekedElement = iterator.next(); 48 | hasPeeked = true; 49 | } 50 | return peekedElement; 51 | } 52 | } -------------------------------------------------------------------------------- /leveldb/src/main/java/com/simsun/common/base/StandardCharsets.java: -------------------------------------------------------------------------------- 1 | package com.simsun.common.base; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | public final class StandardCharsets { 6 | 7 | /** 8 | * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the 9 | * Unicode character set 10 | */ 11 | public static final Charset US_ASCII = Charset.forName("US-ASCII"); 12 | /** 13 | * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1 14 | */ 15 | public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); 16 | /** 17 | * Eight-bit UCS Transformation Format 18 | */ 19 | public static final Charset UTF_8 = Charset.forName("UTF-8"); 20 | /** 21 | * Sixteen-bit UCS Transformation Format, big-endian byte order 22 | */ 23 | public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); 24 | /** 25 | * Sixteen-bit UCS Transformation Format, little-endian byte order 26 | */ 27 | public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); 28 | /** 29 | * Sixteen-bit UCS Transformation Format, byte order identified by an 30 | * optional byte-order mark 31 | */ 32 | public static final Charset UTF_16 = Charset.forName("UTF-16"); 33 | private StandardCharsets() { 34 | throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /leveldb/src/main/java/com/simsun/common/base/Utils.java: -------------------------------------------------------------------------------- 1 | package com.simsun.common.base; 2 | 3 | public class Utils { 4 | public static T requireNonNull(T obj) { 5 | if (obj == null) throw new NullPointerException(); 6 | return obj; 7 | } 8 | 9 | public static T requireNonNull(T obj, String msg) { 10 | if (obj == null) throw new NullPointerException(msg); 11 | return obj; 12 | } 13 | 14 | /** 15 | * Compares two {@code long} values numerically. 16 | * The value returned is identical to what would be returned by: 17 | *

18 |    *    Long.valueOf(x).compareTo(Long.valueOf(y))
19 |    * 
20 | * 21 | * @param x the first {@code long} to compare 22 | * @param y the second {@code long} to compare 23 | * @return the value {@code 0} if {@code x == y}; 24 | * a value less than {@code 0} if {@code x < y}; and 25 | * a value greater than {@code 0} if {@code x > y} 26 | * @since 1.7 27 | */ 28 | public static int compare(long x, long y) { 29 | return (x < y) ? -1 : ((x == y) ? 0 : 1); 30 | } 31 | 32 | public static int compare(byte[] left, byte[] right) { 33 | for (int i = 0, j = 0; i < left.length && j < right.length; i++, j++) { 34 | int a = (left[i] & 0xff); 35 | int b = (right[j] & 0xff); 36 | if (a != b) { 37 | return a - b; 38 | } 39 | } 40 | return left.length - right.length; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/CompressionType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | public enum CompressionType { 21 | NONE(0x00), 22 | SNAPPY(0x01); 23 | 24 | public static CompressionType getCompressionTypeByPersistentId(int persistentId) { 25 | for (CompressionType compressionType : CompressionType.values()) { 26 | if (compressionType.persistentId == persistentId) { 27 | return compressionType; 28 | } 29 | } 30 | throw new IllegalArgumentException("Unknown persistentId " + persistentId); 31 | } 32 | 33 | private final int persistentId; 34 | 35 | CompressionType(int persistentId) { 36 | this.persistentId = persistentId; 37 | } 38 | 39 | public int persistentId() { 40 | return persistentId; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/DB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | import java.io.Closeable; 21 | import java.util.Map; 22 | 23 | /** 24 | * @author Hiram Chirino 25 | */ 26 | public interface DB 27 | extends Iterable>, Closeable { 28 | byte[] get(byte[] key) 29 | throws DBException; 30 | 31 | byte[] get(byte[] key, ReadOptions options) 32 | throws DBException; 33 | 34 | @Override 35 | DBIterator iterator(); 36 | 37 | DBIterator iterator(ReadOptions options); 38 | 39 | void put(byte[] key, byte[] value) 40 | throws DBException; 41 | 42 | void delete(byte[] key) 43 | throws DBException; 44 | 45 | void write(WriteBatch updates) 46 | throws DBException; 47 | 48 | WriteBatch createWriteBatch(); 49 | 50 | /** 51 | * @return null if options.isSnapshot()==false otherwise returns a snapshot 52 | * of the DB after this operation. 53 | */ 54 | Snapshot put(byte[] key, byte[] value, WriteOptions options) 55 | throws DBException; 56 | 57 | /** 58 | * @return null if options.isSnapshot()==false otherwise returns a snapshot 59 | * of the DB after this operation. 60 | */ 61 | Snapshot delete(byte[] key, WriteOptions options) 62 | throws DBException; 63 | 64 | /** 65 | * @return null if options.isSnapshot()==false otherwise returns a snapshot 66 | * of the DB after this operation. 67 | */ 68 | Snapshot write(WriteBatch updates, WriteOptions options) 69 | throws DBException; 70 | 71 | Snapshot getSnapshot(); 72 | 73 | long[] getApproximateSizes(Range... ranges); 74 | 75 | String getProperty(String name); 76 | 77 | /** 78 | * Suspends any background compaction threads. This methods 79 | * returns once the background compactions are suspended. 80 | */ 81 | void suspendCompactions() 82 | throws InterruptedException; 83 | 84 | /** 85 | * Resumes the background compaction threads. 86 | */ 87 | void resumeCompactions(); 88 | 89 | /** 90 | * Force a compaction of the specified key range. 91 | * 92 | * @param begin if null then compaction start from the first key 93 | * @param end if null then compaction ends at the last key 94 | */ 95 | void compactRange(byte[] begin, byte[] end) 96 | throws DBException; 97 | } 98 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/DBComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | import java.util.Comparator; 21 | 22 | /** 23 | * @author Hiram Chirino 24 | */ 25 | public interface DBComparator 26 | extends Comparator { 27 | String name(); 28 | 29 | /** 30 | * If {@code start < limit}, returns a short key in [start,limit). 31 | * Simple comparator implementations should return start unchanged, 32 | */ 33 | byte[] findShortestSeparator(byte[] start, byte[] limit); 34 | 35 | /** 36 | * returns a 'short key' where the 'short key' is greater than or equal to key. 37 | * Simple comparator implementations should return key unchanged, 38 | */ 39 | byte[] findShortSuccessor(byte[] key); 40 | } 41 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/DBException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | /** 21 | * @author Hiram Chirino 22 | */ 23 | public class DBException 24 | extends RuntimeException { 25 | public DBException() { 26 | } 27 | 28 | public DBException(String s) { 29 | super(s); 30 | } 31 | 32 | public DBException(String s, Throwable throwable) { 33 | super(s, throwable); 34 | } 35 | 36 | public DBException(Throwable throwable) { 37 | super(throwable); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/DBFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | 23 | /** 24 | * @author Hiram Chirino 25 | */ 26 | public interface DBFactory { 27 | DB open(File path, Options options) 28 | throws IOException; 29 | 30 | void destroy(File path, Options options) 31 | throws IOException; 32 | 33 | void repair(File path, Options options) 34 | throws IOException; 35 | } 36 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/DBIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | import java.io.Closeable; 21 | import java.util.Iterator; 22 | import java.util.Map; 23 | 24 | /** 25 | * @author Hiram Chirino 26 | */ 27 | public interface DBIterator 28 | extends Iterator>, Closeable { 29 | /** 30 | * Repositions the iterator so the key of the next BlockElement 31 | * returned greater than or equal to the specified targetKey. 32 | */ 33 | void seek(byte[] key); 34 | 35 | /** 36 | * Repositions the iterator so is is at the beginning of the Database. 37 | */ 38 | void seekToFirst(); 39 | 40 | /** 41 | * Returns the next element in the iteration, without advancing the iteration. 42 | */ 43 | Map.Entry peekNext(); 44 | 45 | /** 46 | * @return true if there is a previous entry in the iteration. 47 | */ 48 | boolean hasPrev(); 49 | 50 | /** 51 | * @return the previous element in the iteration and rewinds the iteration. 52 | */ 53 | Map.Entry prev(); 54 | 55 | /** 56 | * @return the previous element in the iteration, without rewinding the iteration. 57 | */ 58 | Map.Entry peekPrev(); 59 | 60 | /** 61 | * Repositions the iterator so it is at the end of of the Database. 62 | */ 63 | void seekToLast(); 64 | } 65 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/Logger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | /** 21 | * @author Hiram Chirino 22 | */ 23 | public interface Logger { 24 | void log(String message); 25 | } 26 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/Options.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | public class Options { 21 | private boolean createIfMissing = true; 22 | private boolean errorIfExists; 23 | private int writeBufferSize = 4 << 20; 24 | 25 | private int maxOpenFiles = 1000; 26 | 27 | private int blockRestartInterval = 16; 28 | private int blockSize = 4 * 1024; 29 | private CompressionType compressionType = CompressionType.NONE; 30 | private boolean verifyChecksums = true; 31 | private boolean paranoidChecks; 32 | private DBComparator comparator; 33 | private Logger logger; 34 | private long cacheSize; 35 | 36 | static void checkArgNotNull(Object value, String name) { 37 | if (value == null) { 38 | throw new IllegalArgumentException("The " + name + " argument cannot be null"); 39 | } 40 | } 41 | 42 | public boolean createIfMissing() { 43 | return createIfMissing; 44 | } 45 | 46 | public Options createIfMissing(boolean createIfMissing) { 47 | this.createIfMissing = createIfMissing; 48 | return this; 49 | } 50 | 51 | public boolean errorIfExists() { 52 | return errorIfExists; 53 | } 54 | 55 | public Options errorIfExists(boolean errorIfExists) { 56 | this.errorIfExists = errorIfExists; 57 | return this; 58 | } 59 | 60 | public int writeBufferSize() { 61 | return writeBufferSize; 62 | } 63 | 64 | public Options writeBufferSize(int writeBufferSize) { 65 | this.writeBufferSize = writeBufferSize; 66 | return this; 67 | } 68 | 69 | public int maxOpenFiles() { 70 | return maxOpenFiles; 71 | } 72 | 73 | public Options maxOpenFiles(int maxOpenFiles) { 74 | this.maxOpenFiles = maxOpenFiles; 75 | return this; 76 | } 77 | 78 | public int blockRestartInterval() { 79 | return blockRestartInterval; 80 | } 81 | 82 | public Options blockRestartInterval(int blockRestartInterval) { 83 | this.blockRestartInterval = blockRestartInterval; 84 | return this; 85 | } 86 | 87 | public int blockSize() { 88 | return blockSize; 89 | } 90 | 91 | public Options blockSize(int blockSize) { 92 | this.blockSize = blockSize; 93 | return this; 94 | } 95 | 96 | public CompressionType compressionType() { 97 | return compressionType; 98 | } 99 | 100 | public Options compressionType(CompressionType compressionType) { 101 | checkArgNotNull(compressionType, "compressionType"); 102 | this.compressionType = compressionType; 103 | return this; 104 | } 105 | 106 | public boolean verifyChecksums() { 107 | return verifyChecksums; 108 | } 109 | 110 | public Options verifyChecksums(boolean verifyChecksums) { 111 | this.verifyChecksums = verifyChecksums; 112 | return this; 113 | } 114 | 115 | public long cacheSize() { 116 | return cacheSize; 117 | } 118 | 119 | public Options cacheSize(long cacheSize) { 120 | this.cacheSize = cacheSize; 121 | return this; 122 | } 123 | 124 | public DBComparator comparator() { 125 | return comparator; 126 | } 127 | 128 | public Options comparator(DBComparator comparator) { 129 | this.comparator = comparator; 130 | return this; 131 | } 132 | 133 | public Logger logger() { 134 | return logger; 135 | } 136 | 137 | public Options logger(Logger logger) { 138 | this.logger = logger; 139 | return this; 140 | } 141 | 142 | public boolean paranoidChecks() { 143 | return paranoidChecks; 144 | } 145 | 146 | public Options paranoidChecks(boolean paranoidChecks) { 147 | this.paranoidChecks = paranoidChecks; 148 | return this; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/Range.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | /** 21 | * @author Hiram Chirino 22 | */ 23 | public class Range { 24 | private final byte[] start; 25 | private final byte[] limit; 26 | 27 | public byte[] limit() { 28 | return limit; 29 | } 30 | 31 | public byte[] start() { 32 | return start; 33 | } 34 | 35 | public Range(byte[] start, byte[] limit) { 36 | Options.checkArgNotNull(start, "start"); 37 | Options.checkArgNotNull(limit, "limit"); 38 | this.limit = limit; 39 | this.start = start; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/ReadOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | public class ReadOptions { 21 | private boolean verifyChecksums; 22 | private boolean fillCache = true; 23 | private Snapshot snapshot; 24 | 25 | public Snapshot snapshot() { 26 | return snapshot; 27 | } 28 | 29 | public ReadOptions snapshot(Snapshot snapshot) { 30 | this.snapshot = snapshot; 31 | return this; 32 | } 33 | 34 | public boolean fillCache() { 35 | return fillCache; 36 | } 37 | 38 | public ReadOptions fillCache(boolean fillCache) { 39 | this.fillCache = fillCache; 40 | return this; 41 | } 42 | 43 | public boolean verifyChecksums() { 44 | return verifyChecksums; 45 | } 46 | 47 | public ReadOptions verifyChecksums(boolean verifyChecksums) { 48 | this.verifyChecksums = verifyChecksums; 49 | return this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/Snapshot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | import java.io.Closeable; 21 | 22 | public interface Snapshot 23 | extends Closeable { 24 | } 25 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/WriteBatch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | import java.io.Closeable; 21 | import java.util.List; 22 | 23 | /** 24 | * @author Hiram Chirino 25 | */ 26 | public interface WriteBatch 27 | extends Closeable { 28 | WriteBatch put(byte[] key, byte[] value); 29 | 30 | WriteBatch delete(byte[] key); 31 | 32 | List getModifiedKeys(); 33 | } 34 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/WriteOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb; 19 | 20 | public class WriteOptions { 21 | private boolean sync; 22 | private boolean snapshot; 23 | 24 | public boolean sync() { 25 | return sync; 26 | } 27 | 28 | public WriteOptions sync(boolean sync) { 29 | this.sync = sync; 30 | return this; 31 | } 32 | 33 | public boolean snapshot() { 34 | return snapshot; 35 | } 36 | 37 | public WriteOptions snapshot(boolean snapshot) { 38 | this.snapshot = snapshot; 39 | return this; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/DbConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | public final class DbConstants { 21 | public static final int MAJOR_VERSION = 0; 22 | public static final int MINOR_VERSION = 1; 23 | 24 | // todo this should be part of the configuration 25 | 26 | /** 27 | * Max number of levels 28 | */ 29 | public static final int NUM_LEVELS = 7; 30 | 31 | /** 32 | * Level-0 compaction is started when we hit this many files. 33 | */ 34 | public static final int L0_COMPACTION_TRIGGER = 4; 35 | 36 | /** 37 | * Soft limit on number of level-0 files. We slow down writes at this point. 38 | */ 39 | public static final int L0_SLOWDOWN_WRITES_TRIGGER = 8; 40 | 41 | /** 42 | * Maximum number of level-0 files. We stop writes at this point. 43 | */ 44 | public static final int L0_STOP_WRITES_TRIGGER = 12; 45 | 46 | /** 47 | * Maximum level to which a new compacted memtable is pushed if it 48 | * does not create overlap. We try to push to level 2 to avoid the 49 | * relatively expensive level 0=>1 compactions and to avoid some 50 | * expensive manifest file operations. We do not push all the way to 51 | * the largest level since that can generate a lot of wasted disk 52 | * space if the same key space is being repeatedly overwritten. 53 | */ 54 | public static final int MAX_MEM_COMPACT_LEVEL = 2; 55 | 56 | private DbConstants() { 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/DbLock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import android.util.Log; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.io.RandomAccessFile; 24 | import java.nio.channels.FileChannel; 25 | import java.nio.channels.FileLock; 26 | import org.iq80.leveldb.util.Closeables; 27 | 28 | import static com.simsun.common.base.Utils.requireNonNull; 29 | import static java.lang.String.format; 30 | 31 | public class DbLock { 32 | public static final String TAG = "DbLock"; 33 | 34 | private final File lockFile; 35 | private final FileChannel channel; 36 | private final FileLock lock; 37 | 38 | public DbLock(File lockFile) throws IOException { 39 | requireNonNull(lockFile, "lockFile is null"); 40 | this.lockFile = lockFile; 41 | 42 | // open and lock the file 43 | channel = new RandomAccessFile(lockFile, "rw").getChannel(); 44 | try { 45 | lock = channel.tryLock(); 46 | } catch (IOException e) { 47 | Closeables.closeQuietly(channel); 48 | throw e; 49 | } 50 | 51 | if (lock == null) { 52 | throw new IOException(format("Unable to acquire lock on '%s'", lockFile.getAbsolutePath())); 53 | } 54 | } 55 | 56 | public boolean isValid() { 57 | return lock.isValid(); 58 | } 59 | 60 | public void release() { 61 | try { 62 | lock.release(); 63 | } catch (IOException e) { 64 | Log.d(TAG, "release", e); 65 | } finally { 66 | Closeables.closeQuietly(channel); 67 | } 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | StringBuilder sb = new StringBuilder(); 73 | sb.append("DbLock"); 74 | sb.append("{lockFile=").append(lockFile); 75 | sb.append(", lock=").append(lock); 76 | sb.append('}'); 77 | return sb.toString(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/FileMetaData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | 22 | public class FileMetaData { 23 | private final long number; 24 | 25 | /** 26 | * File size in bytes 27 | */ 28 | private final long fileSize; 29 | 30 | /** 31 | * Smallest internal key served by table 32 | */ 33 | private final InternalKey smallest; 34 | 35 | /** 36 | * Largest internal key served by table 37 | */ 38 | private final InternalKey largest; 39 | 40 | /** 41 | * Seeks allowed until compaction 42 | */ 43 | // todo this mutable state should be moved elsewhere 44 | private final AtomicInteger allowedSeeks = new AtomicInteger(1 << 30); 45 | 46 | public FileMetaData(long number, long fileSize, InternalKey smallest, InternalKey largest) { 47 | this.number = number; 48 | this.fileSize = fileSize; 49 | this.smallest = smallest; 50 | this.largest = largest; 51 | } 52 | 53 | public long getFileSize() { 54 | return fileSize; 55 | } 56 | 57 | public long getNumber() { 58 | return number; 59 | } 60 | 61 | public InternalKey getSmallest() { 62 | return smallest; 63 | } 64 | 65 | public InternalKey getLargest() { 66 | return largest; 67 | } 68 | 69 | public int getAllowedSeeks() { 70 | return allowedSeeks.get(); 71 | } 72 | 73 | public void setAllowedSeeks(int allowedSeeks) { 74 | this.allowedSeeks.set(allowedSeeks); 75 | } 76 | 77 | public void decrementAllowedSeeks() { 78 | allowedSeeks.getAndDecrement(); 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | StringBuilder sb = new StringBuilder(); 84 | sb.append("FileMetaData"); 85 | sb.append("{number=").append(number); 86 | sb.append(", fileSize=").append(fileSize); 87 | sb.append(", smallest=").append(smallest); 88 | sb.append(", largest=").append(largest); 89 | sb.append(", allowedSeeks=").append(allowedSeeks); 90 | sb.append('}'); 91 | return sb.toString(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/InternalEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.Map.Entry; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import static com.simsun.common.base.StandardCharsets.UTF_8; 24 | import static com.simsun.common.base.Utils.requireNonNull; 25 | 26 | public class InternalEntry implements Entry { 27 | private final InternalKey key; 28 | private final Slice value; 29 | 30 | public InternalEntry(InternalKey key, Slice value) { 31 | requireNonNull(key, "key is null"); 32 | requireNonNull(value, "value is null"); 33 | this.key = key; 34 | this.value = value; 35 | } 36 | 37 | @Override 38 | public InternalKey getKey() { 39 | return key; 40 | } 41 | 42 | @Override 43 | public Slice getValue() { 44 | return value; 45 | } 46 | 47 | /** 48 | * @throws UnsupportedOperationException always 49 | */ 50 | @Override 51 | public final Slice setValue(Slice value) { 52 | throw new UnsupportedOperationException(); 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) { 58 | return true; 59 | } 60 | if (o == null || getClass() != o.getClass()) { 61 | return false; 62 | } 63 | 64 | InternalEntry entry = (InternalEntry) o; 65 | 66 | if (!key.equals(entry.key)) { 67 | return false; 68 | } 69 | if (!value.equals(entry.value)) { 70 | return false; 71 | } 72 | 73 | return true; 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | int result = key.hashCode(); 79 | result = 31 * result + value.hashCode(); 80 | return result; 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | StringBuilder sb = new StringBuilder(); 86 | sb.append("InternalEntry"); 87 | sb.append("{key=").append(key); // todo don't print the real value 88 | sb.append(", value=").append(value.toString(UTF_8)); 89 | sb.append('}'); 90 | return sb.toString(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/InternalKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | import org.iq80.leveldb.util.SliceOutput; 22 | import org.iq80.leveldb.util.Slices; 23 | 24 | import static com.simsun.common.base.Preconditions.checkArgument; 25 | import static com.simsun.common.base.StandardCharsets.UTF_8; 26 | import static com.simsun.common.base.Utils.requireNonNull; 27 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_LONG; 28 | 29 | public class InternalKey { 30 | private final Slice userKey; 31 | private final long sequenceNumber; 32 | private final ValueType valueType; 33 | private int hash; 34 | 35 | public InternalKey(Slice userKey, long sequenceNumber, ValueType valueType) { 36 | requireNonNull(userKey, "userKey is null"); 37 | checkArgument(sequenceNumber >= 0, "sequenceNumber is negative"); 38 | requireNonNull(valueType, "valueType is null"); 39 | 40 | this.userKey = userKey; 41 | this.sequenceNumber = sequenceNumber; 42 | this.valueType = valueType; 43 | } 44 | 45 | public InternalKey(Slice data) { 46 | requireNonNull(data, "data is null"); 47 | checkArgument(data.length() >= SIZE_OF_LONG, "data must be at least %s bytes", SIZE_OF_LONG); 48 | this.userKey = getUserKey(data); 49 | long packedSequenceAndType = data.getLong(data.length() - SIZE_OF_LONG); 50 | this.sequenceNumber = SequenceNumber.unpackSequenceNumber(packedSequenceAndType); 51 | this.valueType = SequenceNumber.unpackValueType(packedSequenceAndType); 52 | } 53 | 54 | public InternalKey(byte[] data) { 55 | this(Slices.wrappedBuffer(data)); 56 | } 57 | 58 | private static Slice getUserKey(Slice data) { 59 | return data.slice(0, data.length() - SIZE_OF_LONG); 60 | } 61 | 62 | public Slice getUserKey() { 63 | return userKey; 64 | } 65 | 66 | public long getSequenceNumber() { 67 | return sequenceNumber; 68 | } 69 | 70 | public ValueType getValueType() { 71 | return valueType; 72 | } 73 | 74 | public Slice encode() { 75 | Slice slice = Slices.allocate(userKey.length() + SIZE_OF_LONG); 76 | SliceOutput sliceOutput = slice.output(); 77 | sliceOutput.writeBytes(userKey); 78 | sliceOutput.writeLong(SequenceNumber.packSequenceAndValueType(sequenceNumber, valueType)); 79 | return slice; 80 | } 81 | 82 | @Override 83 | public boolean equals(Object o) { 84 | if (this == o) { 85 | return true; 86 | } 87 | if (o == null || getClass() != o.getClass()) { 88 | return false; 89 | } 90 | 91 | InternalKey that = (InternalKey) o; 92 | 93 | if (sequenceNumber != that.sequenceNumber) { 94 | return false; 95 | } 96 | if (userKey != null ? !userKey.equals(that.userKey) : that.userKey != null) { 97 | return false; 98 | } 99 | return valueType == that.valueType; 100 | } 101 | 102 | @Override 103 | public int hashCode() { 104 | if (hash == 0) { 105 | int result = userKey != null ? userKey.hashCode() : 0; 106 | result = 31 * result + (int) (sequenceNumber ^ (sequenceNumber >>> 32)); 107 | result = 31 * result + (valueType != null ? valueType.hashCode() : 0); 108 | if (result == 0) { 109 | result = 1; 110 | } 111 | hash = result; 112 | } 113 | return hash; 114 | } 115 | 116 | @Override 117 | public String toString() { 118 | StringBuilder sb = new StringBuilder(); 119 | sb.append("InternalKey"); 120 | sb.append("{key=").append(getUserKey().toString(UTF_8)); // todo don't print the real value 121 | sb.append(", sequenceNumber=").append(getSequenceNumber()); 122 | sb.append(", valueType=").append(getValueType()); 123 | sb.append('}'); 124 | return sb.toString(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/InternalKeyComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import com.simsun.common.base.Utils; 21 | import java.util.Arrays; 22 | import java.util.Comparator; 23 | import java.util.Iterator; 24 | import org.iq80.leveldb.table.UserComparator; 25 | 26 | public class InternalKeyComparator implements Comparator { 27 | private final UserComparator userComparator; 28 | 29 | public InternalKeyComparator(UserComparator userComparator) { 30 | this.userComparator = userComparator; 31 | } 32 | 33 | public UserComparator getUserComparator() { 34 | return userComparator; 35 | } 36 | 37 | public String name() { 38 | return this.userComparator.name(); 39 | } 40 | 41 | @Override 42 | public int compare(InternalKey left, InternalKey right) { 43 | int result = userComparator.compare(left.getUserKey(), right.getUserKey()); 44 | if (result != 0) { 45 | return result; 46 | } 47 | // reverse sorted version numbers 48 | return Utils.compare(right.getSequenceNumber(), left.getSequenceNumber()); 49 | } 50 | 51 | /** 52 | * Returns {@code true} if each element in {@code iterable} after the first is 53 | * greater than or equal to the element that preceded it, according to this 54 | * ordering. Note that this is always true when the iterable has fewer than 55 | * two elements. 56 | */ 57 | public boolean isOrdered(InternalKey... keys) { 58 | return isOrdered(Arrays.asList(keys)); 59 | } 60 | 61 | /** 62 | * Returns {@code true} if each element in {@code iterable} after the first is 63 | * greater than or equal to the element that preceded it, according to this 64 | * ordering. Note that this is always true when the iterable has fewer than 65 | * two elements. 66 | */ 67 | public boolean isOrdered(Iterable keys) { 68 | Iterator iterator = keys.iterator(); 69 | if (!iterator.hasNext()) { 70 | return true; 71 | } 72 | 73 | InternalKey previous = iterator.next(); 74 | while (iterator.hasNext()) { 75 | InternalKey next = iterator.next(); 76 | if (compare(previous, next) > 0) { 77 | return false; 78 | } 79 | previous = next; 80 | } 81 | return true; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/InternalUserComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.table.UserComparator; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import static com.simsun.common.base.Preconditions.checkState; 24 | import static org.iq80.leveldb.impl.SequenceNumber.MAX_SEQUENCE_NUMBER; 25 | 26 | public class InternalUserComparator implements UserComparator { 27 | private final InternalKeyComparator internalKeyComparator; 28 | 29 | public InternalUserComparator(InternalKeyComparator internalKeyComparator) { 30 | this.internalKeyComparator = internalKeyComparator; 31 | } 32 | 33 | @Override 34 | public int compare(Slice left, Slice right) { 35 | return internalKeyComparator.compare(new InternalKey(left), new InternalKey(right)); 36 | } 37 | 38 | @Override 39 | public String name() { 40 | return internalKeyComparator.name(); 41 | } 42 | 43 | @Override 44 | public Slice findShortestSeparator( 45 | Slice start, Slice limit) { 46 | // Attempt to shorten the user portion of the key 47 | Slice startUserKey = new InternalKey(start).getUserKey(); 48 | Slice limitUserKey = new InternalKey(limit).getUserKey(); 49 | 50 | Slice shortestSeparator = 51 | internalKeyComparator.getUserComparator().findShortestSeparator(startUserKey, limitUserKey); 52 | 53 | if (internalKeyComparator.getUserComparator().compare(startUserKey, shortestSeparator) < 0) { 54 | // User key has become larger. Tack on the earliest possible 55 | // number to the shortened user key. 56 | InternalKey newInternalKey = 57 | new InternalKey(shortestSeparator, MAX_SEQUENCE_NUMBER, ValueType.VALUE); 58 | checkState(compare(start, newInternalKey.encode()) < 0); // todo 59 | checkState(compare(newInternalKey.encode(), limit) < 0); // todo 60 | 61 | return newInternalKey.encode(); 62 | } 63 | 64 | return start; 65 | } 66 | 67 | @Override 68 | public Slice findShortSuccessor(Slice key) { 69 | Slice userKey = new InternalKey(key).getUserKey(); 70 | Slice shortSuccessor = internalKeyComparator.getUserComparator().findShortSuccessor(userKey); 71 | 72 | if (internalKeyComparator.getUserComparator().compare(userKey, shortSuccessor) < 0) { 73 | // User key has become larger. Tack on the earliest possible 74 | // number to the shortened user key. 75 | InternalKey newInternalKey = 76 | new InternalKey(shortSuccessor, MAX_SEQUENCE_NUMBER, ValueType.VALUE); 77 | checkState(compare(key, newInternalKey.encode()) < 0); // todo 78 | 79 | return newInternalKey.encode(); 80 | } 81 | 82 | return key; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LogChunkType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import static com.simsun.common.base.Preconditions.checkArgument; 21 | 22 | public enum LogChunkType { 23 | ZERO_TYPE(0), FULL(1), FIRST(2), MIDDLE(3), LAST(4), EOF, BAD_CHUNK, UNKNOWN; 24 | 25 | private final Integer persistentId; 26 | 27 | LogChunkType() { 28 | this.persistentId = null; 29 | } 30 | 31 | LogChunkType(int persistentId) { 32 | this.persistentId = persistentId; 33 | } 34 | 35 | public static LogChunkType getLogChunkTypeByPersistentId(int persistentId) { 36 | for (LogChunkType logChunkType : LogChunkType.values()) { 37 | if (logChunkType.persistentId != null && logChunkType.persistentId == persistentId) { 38 | return logChunkType; 39 | } 40 | } 41 | return UNKNOWN; 42 | } 43 | 44 | public int getPersistentId() { 45 | checkArgument(persistentId != null, "%s is not a persistent chunk type", name()); 46 | return persistentId; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LogConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_BYTE; 21 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_INT; 22 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_SHORT; 23 | 24 | public final class LogConstants { 25 | // todo find new home for these 26 | 27 | public static final int BLOCK_SIZE = 32768; 28 | 29 | // Header is checksum (4 bytes), type (1 byte), length (2 bytes). 30 | public static final int HEADER_SIZE = SIZE_OF_INT + SIZE_OF_BYTE + SIZE_OF_SHORT; 31 | 32 | private LogConstants() { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LogMonitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | public interface LogMonitor { 21 | void corruption(long bytes, String reason); 22 | 23 | void corruption(long bytes, Throwable reason); 24 | } 25 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LogMonitors.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | public final class LogMonitors { 21 | private LogMonitors() { 22 | } 23 | 24 | public static LogMonitor throwExceptionMonitor() { 25 | return new LogMonitor() { 26 | @Override 27 | public void corruption(long bytes, String reason) { 28 | throw new RuntimeException(String.format("corruption of %s bytes: %s", bytes, reason)); 29 | } 30 | 31 | @Override 32 | public void corruption(long bytes, Throwable reason) { 33 | throw new RuntimeException(String.format("corruption of %s bytes", bytes), reason); 34 | } 35 | }; 36 | } 37 | 38 | // todo implement real logging 39 | public static LogMonitor logMonitor() { 40 | return new LogMonitor() { 41 | @Override 42 | public void corruption(long bytes, String reason) { 43 | System.out.println(String.format("corruption of %s bytes: %s", bytes, reason)); 44 | } 45 | 46 | @Override 47 | public void corruption(long bytes, Throwable reason) { 48 | System.out.println(String.format("corruption of %s bytes", bytes)); 49 | reason.printStackTrace(); 50 | } 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LogWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import org.iq80.leveldb.util.Slice; 23 | 24 | public interface LogWriter { 25 | boolean isClosed(); 26 | 27 | void close() throws IOException; 28 | 29 | void delete() throws IOException; 30 | 31 | File getFile(); 32 | 33 | long getFileNumber(); 34 | 35 | // Writes a stream of chunks such that no chunk is split across a block boundary 36 | void addRecord(Slice record, boolean force) throws IOException; 37 | } 38 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/Logs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import org.iq80.leveldb.util.PureJavaCrc32C; 23 | import org.iq80.leveldb.util.Slice; 24 | 25 | public final class Logs { 26 | private Logs() { 27 | } 28 | 29 | public static LogWriter createLogWriter(File file, long fileNumber) throws IOException { 30 | if (Iq80DBFactory.USE_MMAP) { 31 | return new MMapLogWriter(file, fileNumber); 32 | } else { 33 | return new FileChannelLogWriter(file, fileNumber); 34 | } 35 | } 36 | 37 | public static int getChunkChecksum(int chunkTypeId, Slice slice) { 38 | return getChunkChecksum(chunkTypeId, slice.getRawArray(), slice.getRawOffset(), slice.length()); 39 | } 40 | 41 | public static int getChunkChecksum(int chunkTypeId, byte[] buffer, int offset, int length) { 42 | // Compute the crc of the record type and the payload. 43 | PureJavaCrc32C crc32C = new PureJavaCrc32C(); 44 | crc32C.update(chunkTypeId); 45 | crc32C.update(buffer, offset, length); 46 | return crc32C.getMaskedValue(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LookupKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | public class LookupKey { 23 | private final InternalKey key; 24 | 25 | public LookupKey(Slice userKey, long sequenceNumber) { 26 | key = new InternalKey(userKey, sequenceNumber, ValueType.VALUE); 27 | } 28 | 29 | public InternalKey getInternalKey() { 30 | return key; 31 | } 32 | 33 | public Slice getUserKey() { 34 | return key.getUserKey(); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return key.toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/LookupResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | import static com.simsun.common.base.Utils.requireNonNull; 23 | 24 | public class LookupResult { 25 | private final LookupKey key; 26 | private final Slice value; 27 | private final boolean deleted; 28 | 29 | private LookupResult(LookupKey key, Slice value, boolean deleted) { 30 | requireNonNull(key, "key is null"); 31 | this.key = key; 32 | if (value != null) { 33 | this.value = value.slice(); 34 | } else { 35 | this.value = null; 36 | } 37 | this.deleted = deleted; 38 | } 39 | 40 | public static LookupResult ok(LookupKey key, Slice value) { 41 | return new LookupResult(key, value, false); 42 | } 43 | 44 | public static LookupResult deleted(LookupKey key) { 45 | return new LookupResult(key, null, true); 46 | } 47 | 48 | public LookupKey getKey() { 49 | return key; 50 | } 51 | 52 | public Slice getValue() { 53 | if (value == null) { 54 | return null; 55 | } 56 | return value; 57 | } 58 | 59 | public boolean isDeleted() { 60 | return deleted; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/MemTable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import com.simsun.common.base.PeekingIterator; 21 | import com.simsun.common.base.PeekingIteratorImpl; 22 | import java.util.Map.Entry; 23 | import java.util.concurrent.ConcurrentSkipListMap; 24 | import java.util.concurrent.atomic.AtomicLong; 25 | import org.iq80.leveldb.util.InternalIterator; 26 | import org.iq80.leveldb.util.Slice; 27 | 28 | import static com.simsun.common.base.Utils.requireNonNull; 29 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_LONG; 30 | 31 | public class MemTable implements SeekingIterable { 32 | final ConcurrentSkipListMap table; 33 | private final AtomicLong approximateMemoryUsage = new AtomicLong(); 34 | 35 | public MemTable(InternalKeyComparator internalKeyComparator) { 36 | table = new ConcurrentSkipListMap<>(internalKeyComparator); 37 | } 38 | 39 | public boolean isEmpty() { 40 | return table.isEmpty(); 41 | } 42 | 43 | public long approximateMemoryUsage() { 44 | return approximateMemoryUsage.get(); 45 | } 46 | 47 | public void add(long sequenceNumber, ValueType valueType, Slice key, Slice value) { 48 | requireNonNull(valueType, "valueType is null"); 49 | requireNonNull(key, "key is null"); 50 | requireNonNull(valueType, "valueType is null"); 51 | 52 | InternalKey internalKey = new InternalKey(key, sequenceNumber, valueType); 53 | table.put(internalKey, value); 54 | 55 | approximateMemoryUsage.addAndGet(key.length() + SIZE_OF_LONG + value.length()); 56 | } 57 | 58 | public LookupResult get(LookupKey key) { 59 | requireNonNull(key, "key is null"); 60 | 61 | InternalKey internalKey = key.getInternalKey(); 62 | Entry entry = table.ceilingEntry(internalKey); 63 | if (entry == null) { 64 | return null; 65 | } 66 | 67 | InternalKey entryKey = entry.getKey(); 68 | if (entryKey.getUserKey().equals(key.getUserKey())) { 69 | if (entryKey.getValueType() == ValueType.DELETION) { 70 | return LookupResult.deleted(key); 71 | } else { 72 | return LookupResult.ok(key, entry.getValue()); 73 | } 74 | } 75 | return null; 76 | } 77 | 78 | @Override 79 | public MemTableIterator iterator() { 80 | return new MemTableIterator(); 81 | } 82 | 83 | public class MemTableIterator implements InternalIterator { 84 | private PeekingIterator> iterator; 85 | 86 | public MemTableIterator() { 87 | iterator = new PeekingIteratorImpl<>(table.entrySet().iterator()); 88 | } 89 | 90 | @Override 91 | public boolean hasNext() { 92 | return iterator.hasNext(); 93 | } 94 | 95 | @Override 96 | public void seekToFirst() { 97 | iterator = new PeekingIteratorImpl<>(table.entrySet().iterator()); 98 | } 99 | 100 | @Override 101 | public void seek(InternalKey targetKey) { 102 | iterator = new PeekingIteratorImpl<>(table.tailMap(targetKey).entrySet().iterator()); 103 | } 104 | 105 | @Override 106 | public InternalEntry peek() { 107 | Entry entry = iterator.peek(); 108 | return new InternalEntry(entry.getKey(), entry.getValue()); 109 | } 110 | 111 | @Override 112 | public InternalEntry next() { 113 | Entry entry = iterator.next(); 114 | return new InternalEntry(entry.getKey(), entry.getValue()); 115 | } 116 | 117 | @Override 118 | public void remove() { 119 | throw new UnsupportedOperationException(); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/ReadStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | public class ReadStats { 21 | private int seekFileLevel = -1; 22 | private FileMetaData seekFile; 23 | 24 | public void clear() { 25 | seekFileLevel = -1; 26 | seekFile = null; 27 | } 28 | 29 | public int getSeekFileLevel() { 30 | return seekFileLevel; 31 | } 32 | 33 | public void setSeekFileLevel(int seekFileLevel) { 34 | this.seekFileLevel = seekFileLevel; 35 | } 36 | 37 | public FileMetaData getSeekFile() { 38 | return seekFile; 39 | } 40 | 41 | public void setSeekFile(FileMetaData seekFile) { 42 | this.seekFile = seekFile; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/SeekingIterable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.Map.Entry; 21 | 22 | public interface SeekingIterable extends Iterable> { 23 | @Override 24 | SeekingIterator iterator(); 25 | } 26 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/SeekingIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import com.simsun.common.base.PeekingIterator; 21 | import java.util.Map.Entry; 22 | 23 | public interface SeekingIterator extends PeekingIterator> { 24 | /** 25 | * Repositions the iterator so the beginning of this block. 26 | */ 27 | void seekToFirst(); 28 | 29 | /** 30 | * Repositions the iterator so the key of the next BlockElement returned greater than or equal to the specified targetKey. 31 | */ 32 | void seek(K targetKey); 33 | } 34 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/SeekingIteratorAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.Map.Entry; 21 | import java.util.concurrent.atomic.AtomicBoolean; 22 | import org.iq80.leveldb.DBIterator; 23 | import org.iq80.leveldb.util.Slice; 24 | import org.iq80.leveldb.util.Slices; 25 | 26 | import static com.simsun.common.base.Utils.requireNonNull; 27 | 28 | public class SeekingIteratorAdapter implements DBIterator { 29 | private final SnapshotSeekingIterator seekingIterator; 30 | private final AtomicBoolean closed = new AtomicBoolean(false); 31 | 32 | public SeekingIteratorAdapter(SnapshotSeekingIterator seekingIterator) { 33 | this.seekingIterator = seekingIterator; 34 | } 35 | 36 | @Override 37 | public void seekToFirst() { 38 | seekingIterator.seekToFirst(); 39 | } 40 | 41 | @Override 42 | public void seek(byte[] targetKey) { 43 | seekingIterator.seek(Slices.wrappedBuffer(targetKey)); 44 | } 45 | 46 | @Override 47 | public boolean hasNext() { 48 | return seekingIterator.hasNext(); 49 | } 50 | 51 | @Override 52 | public DbEntry next() { 53 | return adapt(seekingIterator.next()); 54 | } 55 | 56 | @Override 57 | public DbEntry peekNext() { 58 | return adapt(seekingIterator.peek()); 59 | } 60 | 61 | @Override 62 | public void close() { 63 | // This is an end user API.. he might screw up and close multiple times. 64 | // but we don't want the close multiple times as reference counts go bad. 65 | if (closed.compareAndSet(false, true)) { 66 | seekingIterator.close(); 67 | } 68 | } 69 | 70 | @Override 71 | public void remove() { 72 | throw new UnsupportedOperationException(); 73 | } 74 | 75 | private DbEntry adapt(Entry entry) { 76 | return new DbEntry(entry.getKey(), entry.getValue()); 77 | } 78 | 79 | // 80 | // todo Implement reverse iterator 81 | // 82 | 83 | @Override 84 | public void seekToLast() { 85 | throw new UnsupportedOperationException(); 86 | } 87 | 88 | @Override 89 | public boolean hasPrev() { 90 | throw new UnsupportedOperationException(); 91 | } 92 | 93 | @Override 94 | public DbEntry prev() { 95 | throw new UnsupportedOperationException(); 96 | } 97 | 98 | @Override 99 | public DbEntry peekPrev() { 100 | throw new UnsupportedOperationException(); 101 | } 102 | 103 | public static class DbEntry implements Entry { 104 | private final Slice key; 105 | private final Slice value; 106 | 107 | public DbEntry(Slice key, Slice value) { 108 | requireNonNull(key, "key is null"); 109 | requireNonNull(value, "value is null"); 110 | this.key = key; 111 | this.value = value; 112 | } 113 | 114 | @Override 115 | public byte[] getKey() { 116 | return key.getBytes(); 117 | } 118 | 119 | public Slice getKeySlice() { 120 | return key; 121 | } 122 | 123 | @Override 124 | public byte[] getValue() { 125 | return value.getBytes(); 126 | } 127 | 128 | public Slice getValueSlice() { 129 | return value; 130 | } 131 | 132 | @Override 133 | public byte[] setValue(byte[] value) { 134 | throw new UnsupportedOperationException(); 135 | } 136 | 137 | @Override 138 | public boolean equals(Object object) { 139 | if (object instanceof Entry) { 140 | Entry that = (Entry) object; 141 | return key.equals(that.getKey()) && value.equals(that.getValue()); 142 | } 143 | return false; 144 | } 145 | 146 | @Override 147 | public int hashCode() { 148 | return key.hashCode() ^ value.hashCode(); 149 | } 150 | 151 | /** 152 | * Returns a string representation of the form {key}={value}. 153 | */ 154 | @Override 155 | public String toString() { 156 | return key + "=" + value; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/SequenceNumber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import static com.simsun.common.base.Preconditions.checkArgument; 21 | import static com.simsun.common.base.Utils.requireNonNull; 22 | 23 | public final class SequenceNumber { 24 | // We leave eight bits empty at the bottom so a type and sequence# 25 | // can be packed together into 64-bits. 26 | public static final long MAX_SEQUENCE_NUMBER = ((0x1L << 56) - 1); 27 | 28 | private SequenceNumber() { 29 | } 30 | 31 | public static long packSequenceAndValueType(long sequence, ValueType valueType) { 32 | checkArgument(sequence <= MAX_SEQUENCE_NUMBER, 33 | "Sequence number is greater than MAX_SEQUENCE_NUMBER" 34 | ); 35 | requireNonNull(valueType, "valueType is null"); 36 | 37 | return (sequence << 8) | valueType.getPersistentId(); 38 | } 39 | 40 | public static ValueType unpackValueType(long num) { 41 | return ValueType.getValueTypeByPersistentId((byte) num); 42 | } 43 | 44 | public static long unpackSequenceNumber(long num) { 45 | return num >>> 8; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/SnapshotImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.concurrent.atomic.AtomicBoolean; 21 | import org.iq80.leveldb.Snapshot; 22 | 23 | public class SnapshotImpl implements Snapshot { 24 | private final AtomicBoolean closed = new AtomicBoolean(); 25 | private final Version version; 26 | private final long lastSequence; 27 | 28 | SnapshotImpl(Version version, long lastSequence) { 29 | this.version = version; 30 | this.lastSequence = lastSequence; 31 | this.version.retain(); 32 | } 33 | 34 | @Override 35 | public void close() { 36 | // This is an end user API.. he might screw up and close multiple times. 37 | // but we don't want the version reference count going bad. 38 | if (closed.compareAndSet(false, true)) { 39 | this.version.release(); 40 | } 41 | } 42 | 43 | public long getLastSequence() { 44 | return lastSequence; 45 | } 46 | 47 | public Version getVersion() { 48 | return version; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return Long.toString(lastSequence); 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) { 59 | return true; 60 | } 61 | if (o == null || getClass() != o.getClass()) { 62 | return false; 63 | } 64 | 65 | SnapshotImpl snapshot = (SnapshotImpl) o; 66 | 67 | if (lastSequence != snapshot.lastSequence) { 68 | return false; 69 | } 70 | if (!version.equals(snapshot.version)) { 71 | return false; 72 | } 73 | 74 | return true; 75 | } 76 | 77 | @Override 78 | public int hashCode() { 79 | int result = version.hashCode(); 80 | result = 31 * result + (int) (lastSequence ^ (lastSequence >>> 32)); 81 | return result; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/SnapshotSeekingIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.AbstractMap; 21 | import java.util.Comparator; 22 | import java.util.Map.Entry; 23 | import org.iq80.leveldb.util.AbstractSeekingIterator; 24 | import org.iq80.leveldb.util.DbIterator; 25 | import org.iq80.leveldb.util.Slice; 26 | 27 | public final class SnapshotSeekingIterator extends AbstractSeekingIterator { 28 | private final DbIterator iterator; 29 | private final SnapshotImpl snapshot; 30 | private final Comparator userComparator; 31 | 32 | public SnapshotSeekingIterator( 33 | DbIterator iterator, SnapshotImpl snapshot, Comparator userComparator) { 34 | this.iterator = iterator; 35 | this.snapshot = snapshot; 36 | this.userComparator = userComparator; 37 | this.snapshot.getVersion().retain(); 38 | } 39 | 40 | public void close() { 41 | this.snapshot.getVersion().release(); 42 | } 43 | 44 | @Override 45 | protected void seekToFirstInternal() { 46 | iterator.seekToFirst(); 47 | findNextUserEntry(null); 48 | } 49 | 50 | @Override 51 | protected void seekInternal(Slice targetKey) { 52 | iterator.seek(new InternalKey(targetKey, snapshot.getLastSequence(), ValueType.VALUE)); 53 | findNextUserEntry(null); 54 | } 55 | 56 | @Override 57 | protected Entry getNextElement() { 58 | if (!iterator.hasNext()) { 59 | return null; 60 | } 61 | 62 | Entry next = iterator.next(); 63 | 64 | // find the next user entry after the key we are about to return 65 | findNextUserEntry(next.getKey().getUserKey()); 66 | 67 | return new AbstractMap.SimpleImmutableEntry<>(next.getKey().getUserKey(), next.getValue()); 68 | } 69 | 70 | private void findNextUserEntry(Slice deletedKey) { 71 | // if there are no more entries, we are done 72 | if (!iterator.hasNext()) { 73 | return; 74 | } 75 | 76 | do { 77 | // Peek the next entry and parse the key 78 | InternalKey internalKey = iterator.peek().getKey(); 79 | 80 | // skip entries created after our snapshot 81 | if (internalKey.getSequenceNumber() > snapshot.getLastSequence()) { 82 | iterator.next(); 83 | continue; 84 | } 85 | 86 | // if the next entry is a deletion, skip all subsequent entries for that key 87 | if (internalKey.getValueType() == ValueType.DELETION) { 88 | deletedKey = internalKey.getUserKey(); 89 | } else if (internalKey.getValueType() == ValueType.VALUE) { 90 | // is this value masked by a prior deletion record? 91 | if (deletedKey == null 92 | || userComparator.compare(internalKey.getUserKey(), deletedKey) > 0) { 93 | return; 94 | } 95 | } 96 | iterator.next(); 97 | } while (iterator.hasNext()); 98 | } 99 | 100 | @Override 101 | public String toString() { 102 | final StringBuilder sb = new StringBuilder(); 103 | sb.append("SnapshotSeekingIterator"); 104 | sb.append("{snapshot=").append(snapshot); 105 | sb.append(", iterator=").append(iterator); 106 | sb.append('}'); 107 | return sb.toString(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/ValueType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | public enum ValueType { 21 | DELETION(0x00), VALUE(0x01); 22 | 23 | private final int persistentId; 24 | 25 | ValueType(int persistentId) { 26 | this.persistentId = persistentId; 27 | } 28 | 29 | public static ValueType getValueTypeByPersistentId(int persistentId) { 30 | switch (persistentId) { 31 | case 0: 32 | return DELETION; 33 | case 1: 34 | return VALUE; 35 | default: 36 | throw new IllegalArgumentException("Unknown persistentId " + persistentId); 37 | } 38 | } 39 | 40 | public int getPersistentId() { 41 | return persistentId; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/WriteBatchImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import java.util.AbstractMap; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.Map.Entry; 24 | import org.iq80.leveldb.WriteBatch; 25 | import org.iq80.leveldb.util.Slice; 26 | import org.iq80.leveldb.util.Slices; 27 | 28 | import static com.simsun.common.base.Utils.requireNonNull; 29 | import static org.iq80.leveldb.impl.Iq80DBFactory.asString; 30 | 31 | public class WriteBatchImpl implements WriteBatch { 32 | private final List> batch = new ArrayList<>(); 33 | private int approximateSize; 34 | 35 | public int getApproximateSize() { 36 | return approximateSize; 37 | } 38 | 39 | public int size() { 40 | return batch.size(); 41 | } 42 | 43 | @Override 44 | public WriteBatchImpl put(byte[] key, byte[] value) { 45 | requireNonNull(key, "key is null"); 46 | requireNonNull(value, "value is null"); 47 | batch.add(new AbstractMap.SimpleImmutableEntry<>(Slices.wrappedBuffer(key), 48 | Slices.wrappedBuffer(value) 49 | )); 50 | approximateSize += 12 + key.length + value.length; 51 | return this; 52 | } 53 | 54 | public WriteBatchImpl put(Slice key, Slice value) { 55 | requireNonNull(key, "key is null"); 56 | requireNonNull(value, "value is null"); 57 | batch.add(new AbstractMap.SimpleImmutableEntry<>(key, value)); 58 | approximateSize += 12 + key.length() + value.length(); 59 | return this; 60 | } 61 | 62 | @Override 63 | public WriteBatchImpl delete(byte[] key) { 64 | requireNonNull(key, "key is null"); 65 | batch.add(new AbstractMap.SimpleImmutableEntry<>(Slices.wrappedBuffer(key), (Slice) null)); 66 | approximateSize += 6 + key.length; 67 | return this; 68 | } 69 | 70 | @Override 71 | public List getModifiedKeys() { 72 | List list = new ArrayList<>(); 73 | for (Entry entry : batch) { 74 | String key = asString(entry.getKey().getBytes()); 75 | list.add(key); 76 | } 77 | return list; 78 | } 79 | 80 | public WriteBatchImpl delete(Slice key) { 81 | requireNonNull(key, "key is null"); 82 | batch.add(new AbstractMap.SimpleImmutableEntry<>(key, (Slice) null)); 83 | approximateSize += 6 + key.length(); 84 | return this; 85 | } 86 | 87 | @Override 88 | public void close() { 89 | } 90 | 91 | public void forEach(Handler handler) { 92 | for (Entry entry : batch) { 93 | Slice key = entry.getKey(); 94 | Slice value = entry.getValue(); 95 | if (value != null) { 96 | handler.put(key, value); 97 | } else { 98 | handler.delete(key); 99 | } 100 | } 101 | } 102 | 103 | public interface Handler { 104 | void put(Slice key, Slice value); 105 | 106 | void delete(Slice key); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/Block.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import java.util.Comparator; 21 | import org.iq80.leveldb.impl.SeekingIterable; 22 | import org.iq80.leveldb.util.Slice; 23 | import org.iq80.leveldb.util.Slices; 24 | 25 | import static com.simsun.common.base.Preconditions.checkArgument; 26 | import static com.simsun.common.base.Utils.requireNonNull; 27 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_INT; 28 | 29 | /** 30 | * Binary Structure 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | *

42 | *

43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | *
nameoffsetlengthdescription
entries4varyEntries in order by key
restart indexvary4 * restart countIndex of prefix compression restarts
restart count04Number of prefix compression restarts (used as index into entries)
62 | */ 63 | public class Block implements SeekingIterable { 64 | private final Slice block; 65 | private final Comparator comparator; 66 | 67 | private final Slice data; 68 | private final Slice restartPositions; 69 | 70 | public Block(Slice block, Comparator comparator) { 71 | requireNonNull(block, "block is null"); 72 | checkArgument( 73 | block.length() >= SIZE_OF_INT, 74 | "Block is corrupt: size must be at least %s block", 75 | SIZE_OF_INT 76 | ); 77 | requireNonNull(comparator, "comparator is null"); 78 | 79 | block = block.slice(); 80 | this.block = block; 81 | this.comparator = comparator; 82 | 83 | // Keys are prefix compressed. Every once in a while the prefix compression is restarted and the full key is written. 84 | // These "restart" locations are written at the end of the file, so you can seek to key without having to read the 85 | // entire file sequentially. 86 | 87 | // key restart count is the last int of the block 88 | int restartCount = block.getInt(block.length() - SIZE_OF_INT); 89 | 90 | if (restartCount > 0) { 91 | // restarts are written at the end of the block 92 | int restartOffset = block.length() - (1 + restartCount) * SIZE_OF_INT; 93 | checkArgument( 94 | restartOffset < block.length() - SIZE_OF_INT, 95 | "Block is corrupt: restart offset count is greater than block size" 96 | ); 97 | restartPositions = block.slice(restartOffset, restartCount * SIZE_OF_INT); 98 | 99 | // data starts at 0 and extends to the restart index 100 | data = block.slice(0, restartOffset); 101 | } else { 102 | data = Slices.EMPTY_SLICE; 103 | restartPositions = Slices.EMPTY_SLICE; 104 | } 105 | } 106 | 107 | public long size() { 108 | return block.length(); 109 | } 110 | 111 | @Override 112 | public BlockIterator iterator() { 113 | return new BlockIterator(data, restartPositions, comparator); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/BlockEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import java.util.Map.Entry; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import static com.simsun.common.base.StandardCharsets.UTF_8; 24 | import static com.simsun.common.base.Utils.requireNonNull; 25 | 26 | /** 27 | * Binary Structure 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | *

39 | *

40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | *
nameoffsetlengthdescription
shared key length0varyvariable length encoded int: size of shared key prefix with the key from the previous entry
non-shared key lengthvaryvaryvariable length encoded int: size of non-shared key suffix in this entry
value lengthvaryvaryvariable length encoded int: size of value in this entry
non-shared keyvarynon-shared key lengthnon-shared key data
valuevaryvalue lengthvalue data
71 | */ 72 | public class BlockEntry implements Entry { 73 | private final Slice key; 74 | private final Slice value; 75 | 76 | public BlockEntry(Slice key, Slice value) { 77 | requireNonNull(key, "key is null"); 78 | requireNonNull(value, "value is null"); 79 | this.key = key; 80 | this.value = value; 81 | } 82 | 83 | @Override 84 | public Slice getKey() { 85 | return key; 86 | } 87 | 88 | @Override 89 | public Slice getValue() { 90 | return value; 91 | } 92 | 93 | /** 94 | * @throws UnsupportedOperationException always 95 | */ 96 | @Override 97 | public final Slice setValue(Slice value) { 98 | throw new UnsupportedOperationException(); 99 | } 100 | 101 | @Override 102 | public boolean equals(Object o) { 103 | if (this == o) { 104 | return true; 105 | } 106 | if (o == null || getClass() != o.getClass()) { 107 | return false; 108 | } 109 | 110 | BlockEntry entry = (BlockEntry) o; 111 | 112 | return key.equals(entry.key) && value.equals(entry.value); 113 | } 114 | 115 | @Override 116 | public int hashCode() { 117 | int result = key.hashCode(); 118 | result = 31 * result + value.hashCode(); 119 | return result; 120 | } 121 | 122 | @Override 123 | public String toString() { 124 | StringBuilder sb = new StringBuilder(); 125 | sb.append("BlockEntry"); 126 | sb.append("{key=").append(key.toString(UTF_8)); // todo don't print the real value 127 | sb.append(", value=").append(value.toString(UTF_8)); 128 | sb.append('}'); 129 | return sb.toString(); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/BlockHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | import org.iq80.leveldb.util.SliceInput; 22 | import org.iq80.leveldb.util.SliceOutput; 23 | import org.iq80.leveldb.util.Slices; 24 | import org.iq80.leveldb.util.VariableLengthQuantity; 25 | 26 | public class BlockHandle { 27 | public static final int MAX_ENCODED_LENGTH = 10 + 10; 28 | 29 | private final long offset; 30 | private final int dataSize; 31 | 32 | BlockHandle(long offset, int dataSize) { 33 | this.offset = offset; 34 | this.dataSize = dataSize; 35 | } 36 | 37 | public static BlockHandle readBlockHandle(SliceInput sliceInput) { 38 | long offset = VariableLengthQuantity.readVariableLengthLong(sliceInput); 39 | long size = VariableLengthQuantity.readVariableLengthLong(sliceInput); 40 | 41 | if (size > Integer.MAX_VALUE) { 42 | throw new IllegalArgumentException("Blocks can not be larger than Integer.MAX_VALUE"); 43 | } 44 | 45 | return new BlockHandle(offset, (int) size); 46 | } 47 | 48 | public static Slice writeBlockHandle(BlockHandle blockHandle) { 49 | Slice slice = Slices.allocate(MAX_ENCODED_LENGTH); 50 | SliceOutput sliceOutput = slice.output(); 51 | writeBlockHandleTo(blockHandle, sliceOutput); 52 | return slice.slice(); 53 | } 54 | 55 | public static void writeBlockHandleTo(BlockHandle blockHandle, SliceOutput sliceOutput) { 56 | VariableLengthQuantity.writeVariableLengthLong(blockHandle.offset, sliceOutput); 57 | VariableLengthQuantity.writeVariableLengthLong(blockHandle.dataSize, sliceOutput); 58 | } 59 | 60 | public long getOffset() { 61 | return offset; 62 | } 63 | 64 | public int getDataSize() { 65 | return dataSize; 66 | } 67 | 68 | public int getFullBlockSize() { 69 | return dataSize + BlockTrailer.ENCODED_LENGTH; 70 | } 71 | 72 | @Override 73 | public boolean equals(Object o) { 74 | if (this == o) { 75 | return true; 76 | } 77 | if (o == null || getClass() != o.getClass()) { 78 | return false; 79 | } 80 | 81 | BlockHandle that = (BlockHandle) o; 82 | 83 | return dataSize == that.dataSize && offset == that.offset; 84 | } 85 | 86 | @Override 87 | public int hashCode() { 88 | int result = (int) (offset ^ (offset >>> 32)); 89 | result = 31 * result + dataSize; 90 | return result; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | StringBuilder sb = new StringBuilder(); 96 | sb.append("BlockHandle"); 97 | sb.append("{offset=").append(offset); 98 | sb.append(", dataSize=").append(dataSize); 99 | sb.append('}'); 100 | return sb.toString(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/BlockTrailer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.CompressionType; 21 | import org.iq80.leveldb.util.Slice; 22 | import org.iq80.leveldb.util.SliceInput; 23 | import org.iq80.leveldb.util.SliceOutput; 24 | import org.iq80.leveldb.util.Slices; 25 | 26 | import static com.simsun.common.base.Utils.requireNonNull; 27 | 28 | public class BlockTrailer { 29 | public static final int ENCODED_LENGTH = 5; 30 | 31 | private final CompressionType compressionType; 32 | private final int crc32c; 33 | 34 | public BlockTrailer(CompressionType compressionType, int crc32c) { 35 | requireNonNull(compressionType, "compressionType is null"); 36 | 37 | this.compressionType = compressionType; 38 | this.crc32c = crc32c; 39 | } 40 | 41 | public static BlockTrailer readBlockTrailer(Slice slice) { 42 | SliceInput sliceInput = slice.input(); 43 | CompressionType compressionType = 44 | CompressionType.getCompressionTypeByPersistentId(sliceInput.readUnsignedByte()); 45 | int crc32c = sliceInput.readInt(); 46 | return new BlockTrailer(compressionType, crc32c); 47 | } 48 | 49 | public static Slice writeBlockTrailer(BlockTrailer blockTrailer) { 50 | Slice slice = Slices.allocate(ENCODED_LENGTH); 51 | writeBlockTrailer(blockTrailer, slice.output()); 52 | return slice; 53 | } 54 | 55 | public static void writeBlockTrailer(BlockTrailer blockTrailer, SliceOutput sliceOutput) { 56 | sliceOutput.writeByte(blockTrailer.getCompressionType().persistentId()); 57 | sliceOutput.writeInt(blockTrailer.getCrc32c()); 58 | } 59 | 60 | public CompressionType getCompressionType() { 61 | return compressionType; 62 | } 63 | 64 | public int getCrc32c() { 65 | return crc32c; 66 | } 67 | 68 | @Override 69 | public boolean equals(Object o) { 70 | if (this == o) { 71 | return true; 72 | } 73 | if (o == null || getClass() != o.getClass()) { 74 | return false; 75 | } 76 | 77 | BlockTrailer that = (BlockTrailer) o; 78 | 79 | if (crc32c != that.crc32c) { 80 | return false; 81 | } 82 | if (compressionType != that.compressionType) { 83 | return false; 84 | } 85 | 86 | return true; 87 | } 88 | 89 | @Override 90 | public int hashCode() { 91 | int result = compressionType.hashCode(); 92 | result = 31 * result + crc32c; 93 | return result; 94 | } 95 | 96 | @Override 97 | public String toString() { 98 | StringBuilder sb = new StringBuilder(); 99 | sb.append("BlockTrailer"); 100 | sb.append("{compressionType=").append(compressionType); 101 | sb.append(", crc32c=0x").append(Integer.toHexString(crc32c)); 102 | sb.append('}'); 103 | return sb.toString(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/BytewiseComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | public class BytewiseComparator implements UserComparator { 23 | @Override 24 | public String name() { 25 | return "leveldb.BytewiseComparator"; 26 | } 27 | 28 | @Override 29 | public int compare(Slice sliceA, Slice sliceB) { 30 | return sliceA.compareTo(sliceB); 31 | } 32 | 33 | @Override 34 | public Slice findShortestSeparator( 35 | Slice start, Slice limit) { 36 | // Find length of common prefix 37 | int sharedBytes = BlockBuilder.calculateSharedBytes(start, limit); 38 | 39 | // Do not shorten if one string is a prefix of the other 40 | if (sharedBytes < Math.min(start.length(), limit.length())) { 41 | // if we can add one to the last shared byte without overflow and the two keys differ by more than 42 | // one increment at this location. 43 | int lastSharedByte = start.getUnsignedByte(sharedBytes); 44 | if (lastSharedByte < 0xff && lastSharedByte + 1 < limit.getUnsignedByte(sharedBytes)) { 45 | Slice result = start.copySlice(0, sharedBytes + 1); 46 | result.setByte(sharedBytes, lastSharedByte + 1); 47 | 48 | assert (compare(result, limit) < 0) : "start must be less than last limit"; 49 | return result; 50 | } 51 | } 52 | return start; 53 | } 54 | 55 | @Override 56 | public Slice findShortSuccessor(Slice key) { 57 | // Find first character that can be incremented 58 | for (int i = 0; i < key.length(); i++) { 59 | int b = key.getUnsignedByte(i); 60 | if (b != 0xff) { 61 | Slice result = key.copySlice(0, i + 1); 62 | result.setByte(i, b + 1); 63 | return result; 64 | } 65 | } 66 | // key is a run of 0xffs. Leave it alone. 67 | return key; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/CustomUserComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.DBComparator; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | public class CustomUserComparator implements UserComparator { 24 | private final DBComparator comparator; 25 | 26 | public CustomUserComparator(DBComparator comparator) { 27 | this.comparator = comparator; 28 | } 29 | 30 | @Override 31 | public String name() { 32 | return comparator.name(); 33 | } 34 | 35 | @Override 36 | public Slice findShortestSeparator(Slice start, Slice limit) { 37 | return new Slice(comparator.findShortestSeparator(start.getBytes(), limit.getBytes())); 38 | } 39 | 40 | @Override 41 | public Slice findShortSuccessor(Slice key) { 42 | return new Slice(comparator.findShortSuccessor(key.getBytes())); 43 | } 44 | 45 | @Override 46 | public int compare(Slice o1, Slice o2) { 47 | return comparator.compare(o1.getBytes(), o2.getBytes()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/FileChannelTable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import java.io.IOException; 21 | import java.nio.ByteBuffer; 22 | import java.nio.channels.FileChannel; 23 | import java.util.Comparator; 24 | import org.iq80.leveldb.util.Slice; 25 | import org.iq80.leveldb.util.Slices; 26 | import org.iq80.leveldb.util.Snappy; 27 | 28 | import static org.iq80.leveldb.CompressionType.SNAPPY; 29 | 30 | public class FileChannelTable extends Table { 31 | 32 | public FileChannelTable( 33 | String name, 34 | FileChannel fileChannel, 35 | Comparator comparator, 36 | boolean verifyChecksums) throws IOException { 37 | super(name, fileChannel, comparator, verifyChecksums); 38 | } 39 | 40 | @Override 41 | protected Footer init() throws IOException { 42 | long size = fileChannel.size(); 43 | ByteBuffer footerData = read(size - Footer.ENCODED_LENGTH, Footer.ENCODED_LENGTH); 44 | return Footer.readFooter(Slices.copiedBuffer(footerData)); 45 | } 46 | 47 | @Override 48 | protected Block readBlock(BlockHandle blockHandle) throws IOException { 49 | // read block trailer 50 | ByteBuffer trailerData = read( 51 | blockHandle.getOffset() + blockHandle.getDataSize(), 52 | BlockTrailer.ENCODED_LENGTH 53 | ); 54 | BlockTrailer blockTrailer = BlockTrailer.readBlockTrailer(Slices.copiedBuffer(trailerData)); 55 | 56 | // todo re-enable crc check when ported to support direct buffers 57 | // // only verify check sums if explicitly asked by the user 58 | // if (verifyChecksums) { 59 | // // checksum data and the compression type in the trailer 60 | // PureJavaCrc32C checksum = new PureJavaCrc32C(); 61 | // checksum.update(data.getRawArray(), data.getRawOffset(), blockHandle.getDataSize() + 1); 62 | // int actualCrc32c = checksum.getMaskedValue(); 63 | // 64 | // checkState(blockTrailer.getCrc32c() == actualCrc32c, "Block corrupted: checksum mismatch"); 65 | // } 66 | 67 | // decompress data 68 | 69 | ByteBuffer uncompressedBuffer = read(blockHandle.getOffset(), blockHandle.getDataSize()); 70 | Slice uncompressedData; 71 | if (blockTrailer.getCompressionType() == SNAPPY) { 72 | synchronized (FileChannelTable.class) { 73 | int uncompressedLength = uncompressedLength(uncompressedBuffer); 74 | if (uncompressedScratch.capacity() < uncompressedLength) { 75 | uncompressedScratch = ByteBuffer.allocateDirect(uncompressedLength); 76 | } 77 | uncompressedScratch.clear(); 78 | 79 | Snappy.uncompress(uncompressedBuffer, uncompressedScratch); 80 | uncompressedData = Slices.copiedBuffer(uncompressedScratch); 81 | } 82 | } else { 83 | uncompressedData = Slices.copiedBuffer(uncompressedBuffer); 84 | } 85 | 86 | return new Block(uncompressedData, comparator); 87 | } 88 | 89 | private ByteBuffer read(long offset, int length) throws IOException { 90 | ByteBuffer uncompressedBuffer = ByteBuffer.allocate(length); 91 | fileChannel.read(uncompressedBuffer, offset); 92 | if (uncompressedBuffer.hasRemaining()) { 93 | throw new IOException("Could not read all the data"); 94 | } 95 | uncompressedBuffer.clear(); 96 | return uncompressedBuffer; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/Footer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | import org.iq80.leveldb.util.SliceInput; 22 | import org.iq80.leveldb.util.SliceOutput; 23 | import org.iq80.leveldb.util.Slices; 24 | 25 | import static com.simsun.common.base.Preconditions.checkArgument; 26 | import static com.simsun.common.base.Utils.requireNonNull; 27 | import static org.iq80.leveldb.table.BlockHandle.readBlockHandle; 28 | import static org.iq80.leveldb.table.BlockHandle.writeBlockHandleTo; 29 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_LONG; 30 | 31 | public class Footer { 32 | public static final int ENCODED_LENGTH = (BlockHandle.MAX_ENCODED_LENGTH * 2) + SIZE_OF_LONG; 33 | 34 | private final BlockHandle metaindexBlockHandle; 35 | private final BlockHandle indexBlockHandle; 36 | 37 | Footer(BlockHandle metaindexBlockHandle, BlockHandle indexBlockHandle) { 38 | this.metaindexBlockHandle = metaindexBlockHandle; 39 | this.indexBlockHandle = indexBlockHandle; 40 | } 41 | 42 | public static Footer readFooter(Slice slice) { 43 | requireNonNull(slice, "slice is null"); 44 | checkArgument( 45 | slice.length() == ENCODED_LENGTH, 46 | "Expected slice.size to be %s but was %s", 47 | ENCODED_LENGTH, 48 | slice.length() 49 | ); 50 | 51 | SliceInput sliceInput = slice.input(); 52 | 53 | // read metaindex and index handles 54 | BlockHandle metaindexBlockHandle = readBlockHandle(sliceInput); 55 | BlockHandle indexBlockHandle = readBlockHandle(sliceInput); 56 | 57 | // skip padding 58 | sliceInput.setPosition(ENCODED_LENGTH - SIZE_OF_LONG); 59 | 60 | // verify magic number 61 | long magicNumber = sliceInput.readUnsignedInt() | (sliceInput.readUnsignedInt() << 32); 62 | checkArgument( 63 | magicNumber == TableBuilder.TABLE_MAGIC_NUMBER, 64 | "File is not a table (bad magic number)" 65 | ); 66 | 67 | return new Footer(metaindexBlockHandle, indexBlockHandle); 68 | } 69 | 70 | public static Slice writeFooter(Footer footer) { 71 | Slice slice = Slices.allocate(ENCODED_LENGTH); 72 | writeFooter(footer, slice.output()); 73 | return slice; 74 | } 75 | 76 | public static void writeFooter(Footer footer, SliceOutput sliceOutput) { 77 | // remember the starting write index so we can calculate the padding 78 | int startingWriteIndex = sliceOutput.size(); 79 | 80 | // write metaindex and index handles 81 | writeBlockHandleTo(footer.getMetaindexBlockHandle(), sliceOutput); 82 | writeBlockHandleTo(footer.getIndexBlockHandle(), sliceOutput); 83 | 84 | // write padding 85 | sliceOutput.writeZero(ENCODED_LENGTH - SIZE_OF_LONG - (sliceOutput.size() 86 | - startingWriteIndex)); 87 | 88 | // write magic number as two (little endian) integers 89 | sliceOutput.writeInt((int) TableBuilder.TABLE_MAGIC_NUMBER); 90 | sliceOutput.writeInt((int) (TableBuilder.TABLE_MAGIC_NUMBER >>> 32)); 91 | } 92 | 93 | public BlockHandle getMetaindexBlockHandle() { 94 | return metaindexBlockHandle; 95 | } 96 | 97 | public BlockHandle getIndexBlockHandle() { 98 | return indexBlockHandle; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/UserComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import java.util.Comparator; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | // todo this interface needs more thought 24 | public interface UserComparator extends Comparator { 25 | String name(); 26 | 27 | Slice findShortestSeparator(Slice start, Slice limit); 28 | 29 | Slice findShortSuccessor(Slice key); 30 | } 31 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/AbstractSeekingIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.util.Map.Entry; 21 | import java.util.NoSuchElementException; 22 | import org.iq80.leveldb.impl.SeekingIterator; 23 | 24 | public abstract class AbstractSeekingIterator implements SeekingIterator { 25 | private Entry nextElement; 26 | 27 | @Override 28 | public final void seekToFirst() { 29 | nextElement = null; 30 | seekToFirstInternal(); 31 | } 32 | 33 | @Override 34 | public final void seek(K targetKey) { 35 | nextElement = null; 36 | seekInternal(targetKey); 37 | } 38 | 39 | @Override 40 | public final boolean hasNext() { 41 | if (nextElement == null) { 42 | nextElement = getNextElement(); 43 | } 44 | return nextElement != null; 45 | } 46 | 47 | @Override 48 | public final Entry next() { 49 | if (nextElement == null) { 50 | nextElement = getNextElement(); 51 | if (nextElement == null) { 52 | throw new NoSuchElementException(); 53 | } 54 | } 55 | 56 | Entry result = nextElement; 57 | nextElement = null; 58 | return result; 59 | } 60 | 61 | @Override 62 | public final Entry peek() { 63 | if (nextElement == null) { 64 | nextElement = getNextElement(); 65 | if (nextElement == null) { 66 | throw new NoSuchElementException(); 67 | } 68 | } 69 | 70 | return nextElement; 71 | } 72 | 73 | @Override 74 | public final void remove() { 75 | throw new UnsupportedOperationException(); 76 | } 77 | 78 | protected abstract void seekToFirstInternal(); 79 | 80 | protected abstract void seekInternal(K targetKey); 81 | 82 | protected abstract Entry getNextElement(); 83 | } 84 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/ByteBufferSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import android.util.Log; 21 | import java.lang.invoke.MethodHandle; 22 | import java.lang.invoke.MethodHandles; 23 | import java.lang.invoke.MethodType; 24 | import java.lang.reflect.Field; 25 | import java.lang.reflect.Method; 26 | import java.nio.ByteBuffer; 27 | import java.nio.MappedByteBuffer; 28 | 29 | public final class ByteBufferSupport { 30 | public static final String TAG = "ByteBufferSupport"; 31 | 32 | private ByteBufferSupport() { 33 | } 34 | 35 | public static void unmap(MappedByteBuffer buffer) { 36 | if (buffer == null) return; 37 | try { 38 | Log.d(TAG, "Try to unmap mapped buffer, but we did nothing"); 39 | } catch (Throwable ignored) { 40 | Log.e(TAG, "", ignored); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/Closeables.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.io.Closeable; 21 | import java.io.IOException; 22 | 23 | public final class Closeables { 24 | private Closeables() { 25 | } 26 | 27 | public static void closeQuietly(Closeable closeable) { 28 | if (closeable == null) { 29 | return; 30 | } 31 | try { 32 | closeable.close(); 33 | } catch (IOException ignored) { 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/IntVector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.util.Arrays; 21 | 22 | import static com.simsun.common.base.Preconditions.checkArgument; 23 | 24 | public class IntVector { 25 | private int size; 26 | private int[] values; 27 | 28 | public IntVector(int initialCapacity) { 29 | this.values = new int[initialCapacity]; 30 | } 31 | 32 | public int size() { 33 | return size; 34 | } 35 | 36 | public void clear() { 37 | size = 0; 38 | } 39 | 40 | public void add(int value) { 41 | checkArgument(size + 1 >= 0, "Invalid minLength: %s", size + 1); 42 | 43 | ensureCapacity(size + 1); 44 | 45 | values[size++] = value; 46 | } 47 | 48 | private void ensureCapacity(int minCapacity) { 49 | if (values.length >= minCapacity) { 50 | return; 51 | } 52 | 53 | int newLength = values.length; 54 | if (newLength == 0) { 55 | newLength = 1; 56 | } else { 57 | newLength <<= 1; 58 | } 59 | values = Arrays.copyOf(values, newLength); 60 | } 61 | 62 | public int[] values() { 63 | return Arrays.copyOf(values, size); 64 | } 65 | 66 | public void write(SliceOutput sliceOutput) { 67 | for (int index = 0; index < size; index++) { 68 | sliceOutput.writeInt(values[index]); 69 | } 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | StringBuilder sb = new StringBuilder(); 75 | sb.append("IntVector"); 76 | sb.append("{size=").append(size); 77 | sb.append(", values=").append(Arrays.toString(values)); 78 | sb.append('}'); 79 | return sb.toString(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/InternalIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import org.iq80.leveldb.impl.InternalKey; 21 | import org.iq80.leveldb.impl.SeekingIterator; 22 | 23 | /** 24 | *

A common interface for internal iterators.

25 | * 26 | * @author Hiram Chirino 27 | */ 28 | public interface InternalIterator extends SeekingIterator {} 29 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/InternalTableIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.util.AbstractMap; 21 | import java.util.Map.Entry; 22 | import org.iq80.leveldb.impl.InternalKey; 23 | 24 | public class InternalTableIterator extends AbstractSeekingIterator 25 | implements InternalIterator { 26 | private final TableIterator tableIterator; 27 | 28 | public InternalTableIterator(TableIterator tableIterator) { 29 | this.tableIterator = tableIterator; 30 | } 31 | 32 | @Override 33 | protected void seekToFirstInternal() { 34 | tableIterator.seekToFirst(); 35 | } 36 | 37 | @Override 38 | public void seekInternal(InternalKey targetKey) { 39 | tableIterator.seek(targetKey.encode()); 40 | } 41 | 42 | @Override 43 | protected Entry getNextElement() { 44 | if (tableIterator.hasNext()) { 45 | Entry next = tableIterator.next(); 46 | return new AbstractMap.SimpleImmutableEntry<>(new InternalKey(next.getKey()), next.getValue()); 47 | } 48 | return null; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | StringBuilder sb = new StringBuilder(); 54 | sb.append("InternalTableIterator"); 55 | sb.append("{fromIterator=").append(tableIterator); 56 | sb.append('}'); 57 | return sb.toString(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/SizeOf.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | public final class SizeOf { 21 | public static final byte SIZE_OF_BYTE = 1; 22 | public static final byte SIZE_OF_SHORT = 2; 23 | public static final byte SIZE_OF_INT = 4; 24 | public static final byte SIZE_OF_LONG = 8; 25 | 26 | private SizeOf() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/SliceComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.util.Comparator; 21 | 22 | public final class SliceComparator implements Comparator { 23 | public static final SliceComparator SLICE_COMPARATOR = new SliceComparator(); 24 | 25 | @Override 26 | public int compare(Slice sliceA, Slice sliceB) { 27 | return sliceA.compareTo(sliceB); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/TableIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.util.Map.Entry; 21 | import org.iq80.leveldb.table.Block; 22 | import org.iq80.leveldb.table.BlockIterator; 23 | import org.iq80.leveldb.table.Table; 24 | 25 | public final class TableIterator extends AbstractSeekingIterator { 26 | private final Table table; 27 | private final BlockIterator blockIterator; 28 | private BlockIterator current; 29 | 30 | public TableIterator(Table table, BlockIterator blockIterator) { 31 | this.table = table; 32 | this.blockIterator = blockIterator; 33 | current = null; 34 | } 35 | 36 | @Override 37 | protected void seekToFirstInternal() { 38 | // reset index to before first and clear the data iterator 39 | blockIterator.seekToFirst(); 40 | current = null; 41 | } 42 | 43 | @Override 44 | protected void seekInternal(Slice targetKey) { 45 | // seek the index to the block containing the key 46 | blockIterator.seek(targetKey); 47 | 48 | // if indexIterator does not have a next, it mean the key does not exist in this iterator 49 | if (blockIterator.hasNext()) { 50 | // seek the current iterator to the key 51 | current = getNextBlock(); 52 | current.seek(targetKey); 53 | } else { 54 | current = null; 55 | } 56 | } 57 | 58 | @Override 59 | protected Entry getNextElement() { 60 | // note: it must be here & not where 'current' is assigned, 61 | // because otherwise we'll have called inputs.next() before throwing 62 | // the first NPE, and the next time around we'll call inputs.next() 63 | // again, incorrectly moving beyond the error. 64 | boolean currentHasNext = false; 65 | while (true) { 66 | if (current != null) { 67 | currentHasNext = current.hasNext(); 68 | } 69 | if (!(currentHasNext)) { 70 | if (blockIterator.hasNext()) { 71 | current = getNextBlock(); 72 | } else { 73 | break; 74 | } 75 | } else { 76 | break; 77 | } 78 | } 79 | if (currentHasNext) { 80 | return current.next(); 81 | } else { 82 | // set current to empty iterator to avoid extra calls to user iterators 83 | current = null; 84 | return null; 85 | } 86 | } 87 | 88 | private BlockIterator getNextBlock() { 89 | Slice blockHandle = blockIterator.next().getValue(); 90 | Block dataBlock = table.openBlock(blockHandle); 91 | return dataBlock.iterator(); 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | StringBuilder sb = new StringBuilder(); 97 | sb.append("ConcatenatingIterator"); 98 | sb.append("{blockIterator=").append(blockIterator); 99 | sb.append(", current=").append(current); 100 | sb.append('}'); 101 | return sb.toString(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/VariableLengthQuantity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.nio.ByteBuffer; 21 | 22 | public final class VariableLengthQuantity { 23 | private VariableLengthQuantity() { 24 | } 25 | 26 | public static int variableLengthSize(int value) { 27 | int size = 1; 28 | while ((value & (~0x7f)) != 0) { 29 | value >>>= 7; 30 | size++; 31 | } 32 | return size; 33 | } 34 | 35 | public static int variableLengthSize(long value) { 36 | int size = 1; 37 | while ((value & (~0x7f)) != 0) { 38 | value >>>= 7; 39 | size++; 40 | } 41 | return size; 42 | } 43 | 44 | public static void writeVariableLengthInt(int value, SliceOutput sliceOutput) { 45 | int highBitMask = 0x80; 46 | if (value < (1 << 7) && value >= 0) { 47 | sliceOutput.writeByte(value); 48 | } else if (value < (1 << 14) && value > 0) { 49 | sliceOutput.writeByte(value | highBitMask); 50 | sliceOutput.writeByte(value >>> 7); 51 | } else if (value < (1 << 21) && value > 0) { 52 | sliceOutput.writeByte(value | highBitMask); 53 | sliceOutput.writeByte((value >>> 7) | highBitMask); 54 | sliceOutput.writeByte(value >>> 14); 55 | } else if (value < (1 << 28) && value > 0) { 56 | sliceOutput.writeByte(value | highBitMask); 57 | sliceOutput.writeByte((value >>> 7) | highBitMask); 58 | sliceOutput.writeByte((value >>> 14) | highBitMask); 59 | sliceOutput.writeByte(value >>> 21); 60 | } else { 61 | sliceOutput.writeByte(value | highBitMask); 62 | sliceOutput.writeByte((value >>> 7) | highBitMask); 63 | sliceOutput.writeByte((value >>> 14) | highBitMask); 64 | sliceOutput.writeByte((value >>> 21) | highBitMask); 65 | sliceOutput.writeByte(value >>> 28); 66 | } 67 | } 68 | 69 | public static void writeVariableLengthLong(long value, SliceOutput sliceOutput) { 70 | // while value more than the first 7 bits set 71 | while ((value & (~0x7f)) != 0) { 72 | sliceOutput.writeByte((int) ((value & 0x7f) | 0x80)); 73 | value >>>= 7; 74 | } 75 | sliceOutput.writeByte((int) value); 76 | } 77 | 78 | public static int readVariableLengthInt(SliceInput sliceInput) { 79 | int result = 0; 80 | for (int shift = 0; shift <= 28; shift += 7) { 81 | int b = sliceInput.readUnsignedByte(); 82 | 83 | // add the lower 7 bits to the result 84 | result |= ((b & 0x7f) << shift); 85 | 86 | // if high bit is not set, this is the last byte in the number 87 | if ((b & 0x80) == 0) { 88 | return result; 89 | } 90 | } 91 | throw new NumberFormatException("last byte of variable length int has high bit set"); 92 | } 93 | 94 | public static int readVariableLengthInt(ByteBuffer sliceInput) { 95 | int result = 0; 96 | for (int shift = 0; shift <= 28; shift += 7) { 97 | int b = sliceInput.get(); 98 | 99 | // add the lower 7 bits to the result 100 | result |= ((b & 0x7f) << shift); 101 | 102 | // if high bit is not set, this is the last byte in the number 103 | if ((b & 0x80) == 0) { 104 | return result; 105 | } 106 | } 107 | throw new NumberFormatException("last byte of variable length int has high bit set"); 108 | } 109 | 110 | public static long readVariableLengthLong(SliceInput sliceInput) { 111 | long result = 0; 112 | for (int shift = 0; shift <= 63; shift += 7) { 113 | long b = sliceInput.readUnsignedByte(); 114 | 115 | // add the lower 7 bits to the result 116 | result |= ((b & 0x7f) << shift); 117 | 118 | // if high bit is not set, this is the last byte in the number 119 | if ((b & 0x80) == 0) { 120 | return result; 121 | } 122 | } 123 | throw new NumberFormatException("last byte of variable length int has high bit set"); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/impl/ApiTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.CompressionType; 21 | import org.iq80.leveldb.DB; 22 | import org.iq80.leveldb.DBException; 23 | import org.iq80.leveldb.DBFactory; 24 | import org.iq80.leveldb.Options; 25 | import org.iq80.leveldb.util.FileUtils; 26 | import org.testng.annotations.Test; 27 | 28 | import java.io.File; 29 | import java.io.IOException; 30 | import java.util.Arrays; 31 | 32 | import static org.iq80.leveldb.impl.Iq80DBFactory.asString; 33 | import static org.iq80.leveldb.impl.Iq80DBFactory.bytes; 34 | import static org.testng.Assert.assertTrue; 35 | 36 | /** 37 | * Test the implemenation via the org.iq80.leveldb API. 38 | * 39 | * @author Hiram Chirino 40 | */ 41 | public class ApiTest 42 | { 43 | private final File databaseDir = FileUtils.createTempDir("leveldb"); 44 | 45 | public void assertEquals(byte[] arg1, byte[] arg2) 46 | { 47 | assertTrue(Arrays.equals(arg1, arg2), asString(arg1) + " != " + asString(arg2)); 48 | } 49 | 50 | private final DBFactory factory = Iq80DBFactory.factory; 51 | 52 | File getTestDirectory(String name) 53 | throws IOException 54 | { 55 | File rc = new File(databaseDir, name); 56 | factory.destroy(rc, new Options().createIfMissing(true)); 57 | rc.mkdirs(); 58 | return rc; 59 | } 60 | 61 | @Test 62 | public void testCompaction() 63 | throws IOException, DBException 64 | { 65 | Options options = new Options().createIfMissing(true).compressionType(CompressionType.NONE); 66 | 67 | File path = getTestDirectory("testCompaction"); 68 | DB db = factory.open(path, options); 69 | 70 | System.out.println("Adding"); 71 | for (int i = 0; i < 1000 * 1000; i++) { 72 | if (i % 100000 == 0) { 73 | System.out.println(" at: " + i); 74 | } 75 | db.put(bytes("key" + i), bytes("value" + i)); 76 | } 77 | 78 | db.close(); 79 | db = factory.open(path, options); 80 | 81 | System.out.println("Deleting"); 82 | for (int i = 0; i < 1000 * 1000; i++) { 83 | if (i % 100000 == 0) { 84 | System.out.println(" at: " + i); 85 | } 86 | db.delete(bytes("key" + i)); 87 | } 88 | 89 | db.close(); 90 | db = factory.open(path, options); 91 | 92 | System.out.println("Adding"); 93 | for (int i = 0; i < 1000 * 1000; i++) { 94 | if (i % 100000 == 0) { 95 | System.out.println(" at: " + i); 96 | } 97 | db.put(bytes("key" + i), bytes("value" + i)); 98 | } 99 | 100 | db.close(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/impl/TestFileChannelLogWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | import org.testng.annotations.Test; 22 | 23 | import java.io.File; 24 | import java.io.FileInputStream; 25 | import java.nio.channels.FileChannel; 26 | 27 | import static org.testng.Assert.assertEquals; 28 | import static org.testng.Assert.fail; 29 | 30 | public class TestFileChannelLogWriter 31 | { 32 | @Test 33 | public void testLogRecordBounds() 34 | throws Exception 35 | { 36 | File file = File.createTempFile("test", ".log"); 37 | try { 38 | int recordSize = LogConstants.BLOCK_SIZE - LogConstants.HEADER_SIZE; 39 | Slice record = new Slice(recordSize); 40 | 41 | LogWriter writer = new FileChannelLogWriter(file, 10); 42 | writer.addRecord(record, false); 43 | writer.close(); 44 | 45 | LogMonitor logMonitor = new AssertNoCorruptionLogMonitor(); 46 | 47 | try (FileInputStream fis = new FileInputStream(file); 48 | FileChannel channel = fis.getChannel()) { 49 | LogReader logReader = new LogReader(channel, logMonitor, true, 0); 50 | int count = 0; 51 | for (Slice slice = logReader.readRecord(); slice != null; slice = logReader.readRecord()) { 52 | assertEquals(slice.length(), recordSize); 53 | count++; 54 | } 55 | assertEquals(count, 1); 56 | } 57 | } 58 | finally { 59 | file.delete(); 60 | } 61 | } 62 | 63 | private static class AssertNoCorruptionLogMonitor 64 | implements LogMonitor 65 | { 66 | @Override 67 | public void corruption(long bytes, String reason) 68 | { 69 | fail("corruption at " + bytes + " reason: " + reason); 70 | } 71 | 72 | @Override 73 | public void corruption(long bytes, Throwable reason) 74 | { 75 | fail("corruption at " + bytes + " reason: " + reason); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/impl/TestMMapLogWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.impl; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | import org.testng.annotations.Test; 22 | 23 | import java.io.File; 24 | import java.io.FileInputStream; 25 | import java.nio.channels.FileChannel; 26 | 27 | import static org.testng.Assert.assertEquals; 28 | import static org.testng.Assert.fail; 29 | 30 | public class TestMMapLogWriter 31 | { 32 | @Test 33 | public void testLogRecordBounds() 34 | throws Exception 35 | { 36 | File file = File.createTempFile("test", ".log"); 37 | try { 38 | int recordSize = LogConstants.BLOCK_SIZE - LogConstants.HEADER_SIZE; 39 | Slice record = new Slice(recordSize); 40 | 41 | LogWriter writer = new MMapLogWriter(file, 10); 42 | writer.addRecord(record, false); 43 | writer.close(); 44 | 45 | LogMonitor logMonitor = new AssertNoCorruptionLogMonitor(); 46 | 47 | FileChannel channel = new FileInputStream(file).getChannel(); 48 | 49 | LogReader logReader = new LogReader(channel, logMonitor, true, 0); 50 | 51 | int count = 0; 52 | for (Slice slice = logReader.readRecord(); slice != null; slice = logReader.readRecord()) { 53 | assertEquals(slice.length(), recordSize); 54 | count++; 55 | } 56 | assertEquals(count, 1); 57 | } 58 | finally { 59 | file.delete(); 60 | } 61 | } 62 | 63 | private static class AssertNoCorruptionLogMonitor 64 | implements LogMonitor 65 | { 66 | @Override 67 | public void corruption(long bytes, String reason) 68 | { 69 | fail("corruption at " + bytes + " reason: " + reason); 70 | } 71 | 72 | @Override 73 | public void corruption(long bytes, Throwable reason) 74 | { 75 | fail("corruption at " + bytes + " reason: " + reason); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/table/FileChannelTableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | import java.io.IOException; 23 | import java.nio.channels.FileChannel; 24 | import java.util.Comparator; 25 | 26 | public class FileChannelTableTest 27 | extends TableTest 28 | { 29 | @Override 30 | protected Table createTable(String name, FileChannel fileChannel, Comparator comparator, boolean verifyChecksums) 31 | throws IOException 32 | { 33 | return new FileChannelTable(name, fileChannel, comparator, verifyChecksums); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/table/MMapTableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.table; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | import java.io.IOException; 23 | import java.nio.channels.FileChannel; 24 | import java.util.Comparator; 25 | 26 | public class MMapTableTest 27 | extends TableTest 28 | { 29 | @Override 30 | protected Table createTable(String name, FileChannel fileChannel, Comparator comparator, boolean verifyChecksums) 31 | throws IOException 32 | { 33 | return new MMapTable(name, fileChannel, comparator, verifyChecksums); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/util/PureJavaCrc32CTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import java.io.UnsupportedEncodingException; 21 | import java.util.Arrays; 22 | import java.util.function.Function; 23 | import org.testng.annotations.DataProvider; 24 | import org.testng.annotations.Test; 25 | 26 | import static java.nio.charset.StandardCharsets.US_ASCII; 27 | import static org.iq80.leveldb.util.PureJavaCrc32C.mask; 28 | import static org.iq80.leveldb.util.PureJavaCrc32C.unmask; 29 | import static org.testng.Assert.assertEquals; 30 | import static org.testng.Assert.assertFalse; 31 | 32 | public class PureJavaCrc32CTest { 33 | private static int computeCrc(byte[] data) { 34 | PureJavaCrc32C crc = new PureJavaCrc32C(); 35 | crc.update(data, 0, data.length); 36 | return crc.getIntValue(); 37 | } 38 | 39 | private static byte[] arrayOf(int size, byte value) { 40 | byte[] result = new byte[size]; 41 | Arrays.fill(result, value); 42 | return result; 43 | } 44 | 45 | @SuppressWarnings("ConstantConditions") 46 | private static byte[] arrayOf(int size, Function generator) { 47 | byte[] result = new byte[size]; 48 | for (int i = 0; i < result.length; ++i) { 49 | result[i] = generator.apply(i); 50 | } 51 | 52 | return result; 53 | } 54 | 55 | private static byte[] arrayOf(int[] bytes) { 56 | byte[] result = new byte[bytes.length]; 57 | for (int i = 0; i < result.length; ++i) { 58 | result[i] = (byte) bytes[i]; 59 | } 60 | 61 | return result; 62 | } 63 | 64 | @Test(dataProvider = "crcs") 65 | public void testCrc(int expectedCrc, byte[] data) { 66 | assertEquals(expectedCrc, computeCrc(data)); 67 | } 68 | 69 | @DataProvider(name = "crcs") 70 | public Object[][] data() { 71 | return new Object[][] { 72 | new Object[] {0x8a9136aa, arrayOf(32, (byte) 0)}, 73 | new Object[] {0x62a8ab43, arrayOf(32, (byte) 0xff)}, 74 | new Object[] {0x46dd794e, arrayOf(32, new Function() { 75 | @Override 76 | public Byte apply(Integer integer) { 77 | return (byte) integer.intValue(); 78 | } 79 | })}, 80 | new Object[] {0x113fdb5c, arrayOf(32, new Function() { 81 | @Override 82 | public Byte apply(Integer integer) { 83 | return (byte) (31 - integer); 84 | } 85 | })}, 86 | new Object[] {0xd9963a56, arrayOf(new int[] { 87 | 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 89 | 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})} 91 | }; 92 | } 93 | 94 | @Test 95 | public void testProducesDifferentCrcs() throws UnsupportedEncodingException { 96 | assertFalse(computeCrc("a".getBytes(US_ASCII)) == computeCrc("foo".getBytes(US_ASCII))); 97 | } 98 | 99 | @Test 100 | public void testComposes() throws UnsupportedEncodingException { 101 | PureJavaCrc32C crc = new PureJavaCrc32C(); 102 | crc.update("hello ".getBytes(US_ASCII), 0, 6); 103 | crc.update("world".getBytes(US_ASCII), 0, 5); 104 | 105 | assertEquals(crc.getIntValue(), computeCrc("hello world".getBytes(US_ASCII))); 106 | } 107 | 108 | @Test 109 | public void testMask() throws UnsupportedEncodingException { 110 | PureJavaCrc32C crc = new PureJavaCrc32C(); 111 | crc.update("foo".getBytes(US_ASCII), 0, 3); 112 | 113 | assertEquals(crc.getMaskedValue(), mask(crc.getIntValue())); 114 | assertFalse(crc.getIntValue() == crc.getMaskedValue(), "crc should not match masked crc"); 115 | assertFalse( 116 | crc.getIntValue() == mask(crc.getMaskedValue()), 117 | "crc should not match double masked crc" 118 | ); 119 | assertEquals(crc.getIntValue(), unmask(crc.getMaskedValue())); 120 | assertEquals(crc.getIntValue(), unmask(unmask(mask(crc.getMaskedValue())))); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/util/SliceComparatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import org.testng.annotations.Test; 21 | 22 | import static com.simsun.common.base.StandardCharsets.UTF_8; 23 | import static org.iq80.leveldb.util.SliceComparator.SLICE_COMPARATOR; 24 | import static org.testng.Assert.assertEquals; 25 | import static org.testng.Assert.assertTrue; 26 | 27 | public class SliceComparatorTest 28 | { 29 | @Test 30 | public void testSliceComparison() 31 | { 32 | assertTrue(SLICE_COMPARATOR.compare( 33 | Slices.copiedBuffer("beer/ipa", UTF_8), 34 | Slices.copiedBuffer("beer/ale", UTF_8)) 35 | > 0); 36 | 37 | assertTrue(SLICE_COMPARATOR.compare( 38 | Slices.wrappedBuffer(new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}), 39 | Slices.wrappedBuffer(new byte[] {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00})) 40 | > 0); 41 | 42 | assertTrue(SLICE_COMPARATOR.compare( 43 | Slices.wrappedBuffer(new byte[] {(byte) 0xFF}), 44 | Slices.wrappedBuffer(new byte[] {(byte) 0x00})) 45 | > 0); 46 | 47 | assertAllEqual(Slices.copiedBuffer("abcdefghijklmnopqrstuvwxyz", UTF_8), 48 | Slices.copiedBuffer("abcdefghijklmnopqrstuvwxyz", UTF_8)); 49 | } 50 | 51 | public static void assertAllEqual(Slice left, Slice right) 52 | { 53 | for (int i = 0; i < left.length(); i++) { 54 | assertEquals(SLICE_COMPARATOR.compare(left.slice(0, i), right.slice(0, i)), 0); 55 | assertEquals(SLICE_COMPARATOR.compare(right.slice(0, i), left.slice(0, i)), 0); 56 | } 57 | // differ in last byte only 58 | for (int i = 1; i < left.length(); i++) { 59 | Slice slice = right.slice(0, i); 60 | int lastReadableByte = slice.length() - 1; 61 | slice.setByte(lastReadableByte, slice.getByte(lastReadableByte) + 1); 62 | assertTrue(SLICE_COMPARATOR.compare(left.slice(0, i), slice) < 0); 63 | assertTrue(SLICE_COMPARATOR.compare(slice, left.slice(0, i)) > 0); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/util/VariableLengthQuantityTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 the original author or authors. 3 | * See the notice.md file distributed with this work for additional 4 | * information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.iq80.leveldb.util; 19 | 20 | import org.testng.annotations.Test; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | public class VariableLengthQuantityTest 25 | { 26 | @Test 27 | public void testWriteVariableLengthInt() 28 | { 29 | testVariableLengthInt(0x0); 30 | testVariableLengthInt(0xf); 31 | testVariableLengthInt(0xff); 32 | testVariableLengthInt(0xfff); 33 | testVariableLengthInt(0xffff); 34 | testVariableLengthInt(0xfffff); 35 | testVariableLengthInt(0xffffff); 36 | testVariableLengthInt(0xfffffff); 37 | testVariableLengthInt(0xffffffff); 38 | } 39 | 40 | private static void testVariableLengthInt(int value) 41 | { 42 | SliceOutput output = Slices.allocate(5).output(); 43 | VariableLengthQuantity.writeVariableLengthInt(value, output); 44 | assertEquals(output.size(), VariableLengthQuantity.variableLengthSize(value)); 45 | int actual = VariableLengthQuantity.readVariableLengthInt(output.slice().input()); 46 | assertEquals(actual, value); 47 | } 48 | 49 | @Test 50 | public void testWriteVariableLengthLong() 51 | { 52 | testVariableLengthLong(0x0L); 53 | testVariableLengthLong(0xfL); 54 | testVariableLengthLong(0xffL); 55 | testVariableLengthLong(0xfffL); 56 | testVariableLengthLong(0xffffL); 57 | testVariableLengthLong(0xfffffL); 58 | testVariableLengthLong(0xffffffL); 59 | testVariableLengthLong(0xfffffffL); 60 | testVariableLengthLong(0xffffffffL); 61 | testVariableLengthLong(0xfffffffffL); 62 | testVariableLengthLong(0xffffffffffL); 63 | testVariableLengthLong(0xfffffffffffL); 64 | testVariableLengthLong(0xffffffffffffL); 65 | testVariableLengthLong(0xfffffffffffffL); 66 | testVariableLengthLong(0xffffffffffffffL); 67 | testVariableLengthLong(0xfffffffffffffffL); 68 | testVariableLengthLong(0xffffffffffffffffL); 69 | } 70 | 71 | private static void testVariableLengthLong(long value) 72 | { 73 | SliceOutput output = Slices.allocate(12).output(); 74 | VariableLengthQuantity.writeVariableLengthLong(value, output); 75 | assertEquals(output.size(), VariableLengthQuantity.variableLengthSize(value)); 76 | long actual = VariableLengthQuantity.readVariableLengthLong(output.slice().input()); 77 | assertEquals(actual, value); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.application' 12 | apply plugin: 'hugo' 13 | 14 | android { 15 | 16 | compileSdkVersion project.TargetSdkVersion 17 | buildToolsVersion project.BuildToolsVersion 18 | 19 | defaultConfig { 20 | applicationId "com.simsun.yasp.samples" 21 | minSdkVersion project.MinSdkVersion 22 | targetSdkVersion project.TargetSdkVersion 23 | versionCode 1 24 | versionName "1.0" 25 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 26 | } 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | } 38 | 39 | dependencies { 40 | implementation fileTree(include: ['*.jar'], dir: 'libs') 41 | implementation "com.android.support:appcompat-v7:${project.AndroidSupportVersion}" 42 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 43 | implementation "com.android.support:design:${project.AndroidSupportVersion}" 44 | implementation "com.android.support:percent:${project.AndroidSupportVersion}" 45 | 46 | implementation project(path: ':yasp-leveldb') 47 | //implementation "com.simsun.yasp:yasp:$POM_VERSION_NAME" 48 | 49 | testImplementation 'junit:junit:4.12' 50 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 51 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/com/simsun/yasp/samples/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.simsun.yasp.samples; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.simsun.yasp", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /sample/src/main/java/com/simsun/yasp/samples/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.simsun.yasp.samples; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.design.widget.Snackbar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_main); 16 | Toolbar toolbar = findViewById(R.id.toolbar); 17 | setSupportActionBar(toolbar); 18 | 19 | FloatingActionButton fab = findViewById(R.id.fab); 20 | fab.setOnClickListener(view -> Snackbar.make( 21 | view, 22 | "Replace with your own action", 23 | Snackbar.LENGTH_LONG 24 | ).setAction("Action", null).show()); 25 | 26 | findViewById(R.id.btn_single_thread).setOnClickListener(v -> { 27 | Intent intent = new Intent(this, SingleThreadActivity.class); 28 | this.startActivity(intent); 29 | }); 30 | 31 | 32 | 33 | findViewById(R.id.btn_mutiple_thread).setOnClickListener(v -> { 34 | Intent intent = new Intent(this, MultipleThreadActivity.class); 35 | this.startActivity(intent); 36 | }); 37 | 38 | findViewById(R.id.btn_simple_benchmark).setOnClickListener(v -> { 39 | Intent intent = new Intent(this, BenchmarkActivity.class); 40 | this.startActivity(intent); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sample/src/main/java/com/simsun/yasp/samples/MultipleThreadActivity.java: -------------------------------------------------------------------------------- 1 | package com.simsun.yasp.samples; 2 | 3 | import android.content.SharedPreferences; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import com.simsun.yasp.YASPContext; 8 | import java.util.concurrent.LinkedBlockingQueue; 9 | import java.util.concurrent.ThreadPoolExecutor; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class MultipleThreadActivity extends AppCompatActivity { 13 | public static final String TAG = "MultipleThreadActivity"; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_mutiple_thread); 19 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(16, 20 | 16, 21 | 10, 22 | TimeUnit.SECONDS, 23 | new LinkedBlockingQueue<>() 24 | ); 25 | 26 | findViewById(R.id.btn_get).setOnClickListener(v -> { 27 | threadPoolExecutor.execute(() -> { 28 | SharedPreferences sp = YASPContext.with(this).getSharedPreferences("multi_thread", 0); 29 | for (int i = 0; i < 100; ++i) { 30 | String value = sp.getString(String.format("Key%d", i), ""); 31 | Log.d(TAG, String.format("%s", value)); 32 | } 33 | }); 34 | }); 35 | 36 | findViewById(R.id.btn_put).setOnClickListener(v -> { 37 | threadPoolExecutor.execute(() -> { 38 | SharedPreferences sp = YASPContext.with(this).getSharedPreferences("multi_thread", 0); 39 | for (int i = 0; i < 100; ++i) { 40 | sp.edit().putString(String.format("Key%d", i), String.format("Value #%d", i)).commit(); 41 | } 42 | }); 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sample/src/main/java/com/simsun/yasp/samples/SingleThreadActivity.java: -------------------------------------------------------------------------------- 1 | package com.simsun.yasp.samples; 2 | 3 | import android.content.SharedPreferences; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import com.simsun.yasp.YASPContext; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | public class SingleThreadActivity extends AppCompatActivity { 12 | public static final String TAG = "SingleThreadActivity"; 13 | 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_single_thread); 19 | final Set strSet = new HashSet<>(); 20 | strSet.add("hello"); 21 | strSet.add("world"); 22 | strSet.add("this"); 23 | strSet.add("is"); 24 | strSet.add("a"); 25 | strSet.add("just so so"); 26 | strSet.add("sp implementation"); 27 | 28 | findViewById(R.id.btn_get).setOnClickListener(v -> { 29 | SharedPreferences sp = YASPContext.with(this).getSharedPreferences("single_thread", 0); 30 | for (int i = 0; i < 1000; ++i) { 31 | Set values = sp.getStringSet(String.format("KeyNew%s", i), new HashSet<>()); 32 | StringBuilder sb = new StringBuilder(); 33 | for (String str : values) { 34 | sb.append(str).append(" "); 35 | } 36 | Log.d(TAG, sb.toString()); 37 | } 38 | }); 39 | 40 | findViewById(R.id.btn_put).setOnClickListener(v -> { 41 | SharedPreferences sp = YASPContext.with(this).getSharedPreferences("single_thread", 0); 42 | for (int i = 0; i < 1000; ++i) { 43 | sp.edit().putStringSet(String.format("KeyNew%s", i), strSet).apply(); 44 | } 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_benchmark.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 |