├── .github ├── CODEOWNERS └── workflows │ ├── publish.yml │ └── build.yml ├── .gitattributes ├── leveldb └── src │ ├── main │ ├── resources │ │ └── org │ │ │ └── iq80 │ │ │ └── leveldb │ │ │ └── impl │ │ │ └── version.txt │ └── java │ │ └── org │ │ └── iq80 │ │ └── leveldb │ │ ├── iterator │ │ ├── SliceIterator.java │ │ ├── InternalIterator.java │ │ ├── Direction.java │ │ ├── InternalTableIterator.java │ │ ├── SeekingIterators.java │ │ └── DbIterator.java │ │ ├── impl │ │ ├── LogMonitor.java │ │ ├── LogConstants.java │ │ ├── LookupKey.java │ │ ├── ValueHolder.java │ │ ├── ValueType.java │ │ ├── InsertIntoHandler.java │ │ ├── ReadStats.java │ │ ├── InternalKeyComparator.java │ │ ├── SequenceNumber.java │ │ ├── LogChunkType.java │ │ ├── LookupResult.java │ │ ├── KeyMatchingLookup.java │ │ ├── LogMonitors.java │ │ ├── Logs.java │ │ ├── DbConstants.java │ │ ├── InternalFilterPolicy.java │ │ ├── InternalEntry.java │ │ ├── FileMetaData.java │ │ ├── MemTable.java │ │ ├── Iq80DBFactory.java │ │ └── InternalUserComparator.java │ │ ├── env │ │ ├── DbLock.java │ │ ├── NoOpLogger.java │ │ ├── RandomInputFile.java │ │ ├── WritableFile.java │ │ ├── SequentialFile.java │ │ └── File.java │ │ ├── util │ │ ├── SizeOf.java │ │ ├── SliceComparator.java │ │ ├── ILRUCache.java │ │ ├── IntVector.java │ │ ├── LRUCache.java │ │ ├── Hash.java │ │ ├── LogMessageFormatter.java │ │ ├── Closeables.java │ │ └── ZLib.java │ │ ├── table │ │ ├── UserComparator.java │ │ ├── BlockHandleSliceWeigher.java │ │ ├── KeyValueFunction.java │ │ ├── CacheKey.java │ │ ├── RestartPositions.java │ │ ├── CustomUserComparator.java │ │ ├── FilterPolicy.java │ │ ├── FilterBlockReader.java │ │ └── BytewiseComparator.java │ │ ├── memenv │ │ ├── MemWritableFile.java │ │ ├── MemRandomInputFile.java │ │ └── MemSequentialFile.java │ │ └── fileenv │ │ ├── SequentialFileImpl.java │ │ ├── UnbufferedWritableFile.java │ │ ├── FileLogger.java │ │ ├── MmapLimiter.java │ │ ├── MMRandomInputFile.java │ │ ├── ByteBufferSupport.java │ │ └── FileLock.java │ └── test │ └── java │ └── org │ └── iq80 │ └── leveldb │ ├── table │ ├── InMemoryTableTest.java │ ├── MMRandomInputFileTableTest.java │ └── UnbufferedRandomInputFileTableTest.java │ ├── memenv │ ├── MemFsTest.java │ └── MemFileTest.java │ ├── impl │ ├── WriteBatchImplTest.java │ ├── VersionEditTest.java │ └── InternalKeyTest.java │ ├── util │ ├── HashTest.java │ ├── SliceComparatorTest.java │ ├── TestUtils.java │ ├── SafeListBuilderTest.java │ └── VariableLengthQuantityTest.java │ ├── fileenv │ ├── FileLoggerTest.java │ ├── FileLockTest.java │ └── SequentialFileImplTest.java │ └── iterator │ └── SeekingDBIteratorAdapter.java ├── notice.md ├── CODE_OF_CONDUCT.md ├── .gitignore ├── SUPPORT.md ├── CONTRIBUTING.md ├── src ├── license │ └── LICENSE-HEADER.txt └── site │ └── site.xml ├── leveldb-api ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── iq80 │ │ └── leveldb │ │ ├── Snapshot.java │ │ ├── DBException.java │ │ ├── XFilterPolicy.java │ │ ├── WriteBatch.java │ │ ├── Range.java │ │ ├── Logger.java │ │ ├── DBFactory.java │ │ ├── CompressionType.java │ │ ├── DBIterator.java │ │ ├── DBComparator.java │ │ ├── ReadOptions.java │ │ └── WriteOptions.java │ └── test │ └── java │ └── org │ └── iq80 │ └── leveldb │ └── OptionsTest.java ├── README.md ├── SECURITY.md └── leveldb-benchmark └── pom.xml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @HiveGamesOSS/chunker -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.java text eol=lf 3 | -------------------------------------------------------------------------------- /leveldb/src/main/resources/org/iq80/leveldb/impl/version.txt: -------------------------------------------------------------------------------- 1 | ${project.version} -------------------------------------------------------------------------------- /notice.md: -------------------------------------------------------------------------------- 1 | LevelDB Copyright Notices 2 | ========================= 3 | 4 | * Copyright 2011 Dain Sundstrom 5 | * Copyright 2011 FuseSource Corp. http://fusesource.com 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Open Source Code of Conduct 2 | 3 | This project has adopted the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | /var 3 | pom.xml.versionsBackup 4 | test-output/ 5 | /atlassian-ide-plugin.x 6 | .idea 7 | .*.swp 8 | .*.swo 9 | leveldb-c 10 | *~ 11 | *.swp 12 | .idea 13 | .idea/* 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .DS_Store 18 | .scala_dependencies 19 | .project 20 | .classpath 21 | .settings 22 | eclipse-classes 23 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project does not allow issues / PRs, if you would like help with Chunker related issues please file an issue on our 6 | main repository referencing this project if needed. 7 | 8 | ## Hive Games Support Policy 9 | 10 | Support for this project is limited to the Chunker scope. 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to leveldb-mcpe-java 2 | 3 | Thanks for your interest in contributing to this repository. 4 | 5 | If you find a bug in Chunker or wish to request adding a feature please make a GitHub issue on the Chunker repository, 6 | searching first to ensure it doesn't exist already. 7 | 8 | We don't accept contributions currently for this repository though you are more than welcome to fork it and add your own 9 | contributions, you are also welcome to create an issue on our main Chunker repository referencing your changes for 10 | review. 11 | 12 | This project is maintained by Hive Games. 13 | -------------------------------------------------------------------------------- /src/license/LICENSE-HEADER.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011 the original author or authors. 2 | See the notice.md file distributed with this work for additional 3 | information regarding copyright ownership. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /leveldb-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.hivemc.leveldb 7 | leveldb-project 8 | 1.1.0 9 | 10 | 11 | leveldb-api 12 | ${project.artifactId} 13 | High level Java API for LevelDB 14 | 15 | 16 | ${project.parent.basedir} 17 | 18 | 19 | 20 | 21 | org.testng 22 | testng 23 | test 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/iterator/SliceIterator.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.iterator; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | public interface SliceIterator extends SeekingIterator 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /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 | { 22 | void corruption(long bytes, String reason); 23 | 24 | void corruption(long bytes, Throwable reason); 25 | } 26 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/table/InMemoryTableTest.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.env.Env; 21 | import org.iq80.leveldb.memenv.MemEnv; 22 | 23 | public class InMemoryTableTest 24 | extends TableTest 25 | { 26 | @Override 27 | protected Env getEnv() 28 | { 29 | return MemEnv.createEnv(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/env/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.env; 19 | 20 | /** 21 | * DB lock information 22 | */ 23 | public interface DbLock 24 | { 25 | /** 26 | * Is lock valid and not released 27 | * @return true, if acquired 28 | */ 29 | boolean isValid(); 30 | 31 | /** 32 | * Release DB lock 33 | */ 34 | void release(); 35 | } 36 | -------------------------------------------------------------------------------- /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 | { 22 | public static final byte SIZE_OF_BYTE = 1; 23 | public static final byte SIZE_OF_SHORT = 2; 24 | public static final byte SIZE_OF_INT = 4; 25 | public static final byte SIZE_OF_LONG = 8; 26 | 27 | private SizeOf() 28 | { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /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 org.iq80.leveldb.util.Slice; 21 | 22 | import java.util.Comparator; 23 | 24 | public interface UserComparator 25 | extends Comparator 26 | { 27 | String name(); 28 | 29 | Slice findShortestSeparator(Slice start, Slice limit); 30 | 31 | Slice findShortSuccessor(Slice key); 32 | } 33 | -------------------------------------------------------------------------------- /leveldb-api/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 | /** 23 | * Abstract handle to particular state of a DB. 24 | * A Snapshot can therefore be safely accessed from multiple threads 25 | * without any external synchronization. 26 | * 27 | * Can't be used after close 28 | */ 29 | public interface Snapshot 30 | extends Closeable 31 | { 32 | } 33 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/env/NoOpLogger.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.env; 19 | 20 | import org.iq80.leveldb.Logger; 21 | 22 | public class NoOpLogger implements Logger 23 | { 24 | @Override 25 | public void log(String message) 26 | { 27 | /* no op */ 28 | } 29 | 30 | @Override 31 | public void log(String message, Object... args) 32 | { 33 | /* no op */ 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/iterator/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.iterator; 19 | 20 | import org.iq80.leveldb.impl.InternalKey; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | /** 24 | *

A common interface for internal iterators.

25 | * 26 | * @author Hiram Chirino 27 | */ 28 | public interface InternalIterator 29 | extends SeekingIterator 30 | { 31 | } 32 | -------------------------------------------------------------------------------- /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 23 | implements Comparator 24 | { 25 | public static final SliceComparator SLICE_COMPARATOR = new SliceComparator(); 26 | 27 | @Override 28 | public int compare(Slice sliceA, Slice sliceB) 29 | { 30 | return sliceA.compareTo(sliceB); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a package using Maven and then publish it to maven central 2 | 3 | name: Publish Maven Package 4 | 5 | on: 6 | release: 7 | types: [ created ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | permissions: 14 | contents: read 15 | packages: write 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Set up JDK 17 20 | uses: actions/setup-java@v3 21 | with: 22 | java-version: '17' 23 | distribution: 'temurin' 24 | server-id: central # Value of the distributionManagement/repository/id field of the pom.xml 25 | server-username: OSSRH_USERNAME 26 | server-password: OSSRH_PASSWORD 27 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} 28 | settings-path: ${{ github.workspace }} # location for the settings.xml file 29 | 30 | - name: Publish to Maven Central 31 | run: mvn --no-transfer-progress --batch-mode deploy -s $GITHUB_WORKSPACE/settings.xml # Change to deploy when ready 32 | env: 33 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 34 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 35 | MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/iterator/Direction.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.iterator; 19 | 20 | enum Direction 21 | { 22 | START_OF_ITERATOR(false), 23 | RELEASED(false), 24 | END_OF_ITERATOR(false), 25 | REVERSE(true), 26 | FORWARD(true); 27 | 28 | private boolean valid; 29 | 30 | Direction(boolean valid) 31 | { 32 | this.valid = valid; 33 | } 34 | 35 | public boolean isValid() 36 | { 37 | return valid; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/table/MMRandomInputFileTableTest.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.env.Env; 21 | import org.iq80.leveldb.fileenv.EnvImpl; 22 | import org.iq80.leveldb.fileenv.MmapLimiter; 23 | 24 | public class MMRandomInputFileTableTest 25 | extends TableTest 26 | { 27 | @Override 28 | protected Env getEnv() 29 | { 30 | //force MMap files 31 | return EnvImpl.createEnv(MmapLimiter.newLimiter(1000)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/BlockHandleSliceWeigher.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 | 19 | package org.iq80.leveldb.table; 20 | 21 | import com.google.common.cache.Weigher; 22 | import org.iq80.leveldb.util.Slice; 23 | 24 | /** 25 | * @author Honore Vasconcelos 26 | */ 27 | public class BlockHandleSliceWeigher implements Weigher 28 | { 29 | @Override 30 | public int weigh(CacheKey key, Slice value) 31 | { 32 | //approximate weigher 33 | return 64 + value.getRawArray().length; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/table/UnbufferedRandomInputFileTableTest.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.env.Env; 21 | import org.iq80.leveldb.fileenv.EnvImpl; 22 | import org.iq80.leveldb.fileenv.MmapLimiter; 23 | 24 | public class UnbufferedRandomInputFileTableTest 25 | extends TableTest 26 | { 27 | @Override 28 | protected Env getEnv() 29 | { 30 | //disable memory mapped files 31 | return EnvImpl.createEnv(MmapLimiter.newLimiter(0)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/KeyValueFunction.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 | 19 | package org.iq80.leveldb.table; 20 | 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | /** 24 | * @author Honore Vasconcelos 25 | */ 26 | public interface KeyValueFunction 27 | { 28 | /** 29 | * Function to apply on first entry after seeking in a table. 30 | * 31 | * @param internalKey internal key 32 | * @param value associated value 33 | * @return transformed key/value 34 | */ 35 | T apply(Slice internalKey, Slice value); 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Java CI with Maven 10 | 11 | on: 12 | push: 13 | branches: [ "main" ] 14 | pull_request: 15 | branches: [ "main" ] 16 | 17 | permissions: 18 | contents: write 19 | 20 | jobs: 21 | build: 22 | 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Set up JDK 17 28 | uses: actions/setup-java@v3 29 | with: 30 | java-version: '17' 31 | distribution: 'temurin' 32 | cache: maven 33 | - name: Build with Maven 34 | run: mvn -B package --file pom.xml 35 | 36 | # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive 37 | - name: Update dependency graph 38 | uses: advanced-security/maven-dependency-submission-action@f97a4078d80bca790cd68e93a88da11a056ac0a3 39 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/memenv/MemFsTest.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.memenv; 19 | 20 | import org.iq80.leveldb.env.File; 21 | import org.testng.annotations.Test; 22 | 23 | import static org.testng.Assert.assertFalse; 24 | import static org.testng.Assert.assertTrue; 25 | 26 | public class MemFsTest 27 | { 28 | @Test 29 | public void testListFiles() 30 | { 31 | File abc = MemEnv.createEnv().createTempDir("prefix"); 32 | assertTrue(abc.isDirectory()); 33 | assertTrue(abc.exists()); 34 | assertFalse(abc.isFile()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /leveldb-api/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 | { 26 | public DBException() 27 | { 28 | } 29 | 30 | public DBException(String s) 31 | { 32 | super(s); 33 | } 34 | 35 | public DBException(String s, Throwable throwable) 36 | { 37 | super(s, throwable); 38 | } 39 | 40 | public DBException(Throwable throwable) 41 | { 42 | super(throwable); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LevelDB MCPE in Java 2 | 3 | This project is a fork of https://github.com/pcmind/leveldb aiming to implement the changes made 4 | in https://github.com/Mojang/leveldb-mcpe/ where relevant to allow the library to read MCPE. 5 | 6 | For more information see the original repository on use cases / API usage. 7 | 8 | Building 9 | -------- 10 | 11 | **Requirements** 12 | 13 | - Git 14 | - Java 11 or higher 15 | - Maven 16 | 17 | **Steps** 18 | 19 | 1. Clone this repository via `git clone git://github.com/HiveGamesOSS/leveldb-mcpe-java.git`. 20 | 2. Build the project via `mvn clean install`. 21 | 3. Obtain the library from `target/` folder. 22 | 23 | Library Usage 24 | -------- 25 | 26 | You can use the following in your maven pom.xml: 27 | 28 | ```xml 29 | 30 | 31 | com.hivemc.leveldb 32 | leveldb 33 | 1.0.0 34 | 35 | ``` 36 | 37 | ```xml 38 | 39 | 40 | com.hivemc.leveldb 41 | leveldb-api 42 | 1.0.0 43 | 44 | ``` 45 | 46 | This library is aimed as a drop in replacement to the original fork https://github.com/pcmind/leveldb. 47 | 48 | License 49 | -------- 50 | 51 | Details of the LICENSE can be found in the license.txt, this fork maintains the original license for all code and 52 | modifications. 53 | -------------------------------------------------------------------------------- /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 | { 26 | // todo find new home for these 27 | 28 | public static final int BLOCK_SIZE = 32768; 29 | 30 | // Header is checksum (4 bytes), type (1 byte), length (2 bytes). 31 | public static final int HEADER_SIZE = SIZE_OF_INT + SIZE_OF_BYTE + SIZE_OF_SHORT; 32 | 33 | private LogConstants() 34 | { 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | com.googlecode.fluido-skin 23 | fluido-skin 24 | 1.3 25 | 26 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /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 | { 24 | private final InternalKey key; 25 | 26 | public LookupKey(Slice userKey, long sequenceNumber) 27 | { 28 | key = new InternalKey(userKey, sequenceNumber, ValueType.VALUE); 29 | } 30 | 31 | public InternalKey getInternalKey() 32 | { 33 | return key; 34 | } 35 | 36 | public Slice getUserKey() 37 | { 38 | return key.getUserKey(); 39 | } 40 | 41 | @Override 42 | public String toString() 43 | { 44 | return key.toString(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /leveldb-api/src/main/java/org/iq80/leveldb/XFilterPolicy.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 | * A database can be configured with a custom FilterPolicy object. 22 | * This object is responsible for creating a small filter from a set 23 | * of keys. These filters are stored in leveldb and are consulted 24 | * automatically by leveldb to decide whether or not to read some 25 | * information from disk. In many cases, a filter can cut down the 26 | * number of disk seeks form a handful to a single disk seek per 27 | * DB::Get() call. 28 | *

29 | * Most people will want to use the builtin bloom filter support (see 30 | * NewBloomFilterPolicy() below). 31 | * 32 | * @author Honore Vasconcelos 33 | */ 34 | public interface XFilterPolicy 35 | { 36 | } 37 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/ValueHolder.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 | /** 21 | * Value holder for reference modification like in C++ 22 | */ 23 | final class ValueHolder 24 | { 25 | private V value; 26 | 27 | public ValueHolder(V value) 28 | { 29 | this.value = value; 30 | } 31 | 32 | /** 33 | * Setter for property 'value'. 34 | * 35 | * @param value Value to set for property 'value'. 36 | */ 37 | public void setValue(V value) 38 | { 39 | this.value = value; 40 | } 41 | 42 | /** 43 | * Getter for property 'value'. 44 | * 45 | * @return Value for property 'value'. 46 | */ 47 | public V getValue() 48 | { 49 | return value; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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 | { 22 | DELETION(0x00), 23 | VALUE(0x01); 24 | 25 | public static ValueType getValueTypeByPersistentId(int persistentId) 26 | { 27 | switch (persistentId) { 28 | case 0: 29 | return DELETION; 30 | case 1: 31 | return VALUE; 32 | default: 33 | throw new IllegalArgumentException("Unknown persistentId " + persistentId); 34 | } 35 | } 36 | 37 | private final int persistentId; 38 | 39 | ValueType(int persistentId) 40 | { 41 | this.persistentId = persistentId; 42 | } 43 | 44 | public int getPersistentId() 45 | { 46 | return persistentId; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/env/RandomInputFile.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.env; 19 | 20 | import java.io.Closeable; 21 | import java.io.IOException; 22 | import java.nio.ByteBuffer; 23 | 24 | /** 25 | * Read only data source for table data/blocks. 26 | * 27 | * @author Honore Vasconcelos 28 | */ 29 | public interface RandomInputFile extends Closeable 30 | { 31 | /** 32 | * Source size 33 | */ 34 | long size(); 35 | 36 | /** 37 | * Read {@code length} bytes from source from {@code source} starting at {@code offset} position. 38 | * @param offset position for read start 39 | * @param length length of the bytes to read 40 | * @return read only view of the data. 41 | * @throws IOException on any exception will accessing source media 42 | */ 43 | ByteBuffer read(long offset, int length) throws IOException; 44 | } 45 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/env/WritableFile.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.env; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | 22 | import java.io.Closeable; 23 | import java.io.IOException; 24 | 25 | /** 26 | * A file abstraction for sequential writing. The implementation 27 | * must provide buffering since callers may append small fragments 28 | * at a time to the file. 29 | * 30 | * @author Honore Vasconcelos 31 | */ 32 | public interface WritableFile extends Closeable 33 | { 34 | /** 35 | * Append {@code data} to current file position. 36 | * @param data data to append 37 | * @throws IOException on any error accessing file 38 | */ 39 | void append(Slice data) throws IOException; 40 | 41 | /** 42 | * Force sync bytes to filesystem. 43 | * @throws IOException on any error accessing file 44 | */ 45 | void force() throws IOException; 46 | } 47 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/CacheKey.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 | public final class CacheKey 21 | { 22 | private final long id; 23 | private final BlockHandle key; 24 | 25 | CacheKey(final long id, BlockHandle key) 26 | { 27 | this.id = id; 28 | this.key = key; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) 33 | { 34 | if (this == o) { 35 | return true; 36 | } 37 | if (o == null || getClass() != o.getClass()) { 38 | return false; 39 | } 40 | 41 | CacheKey cacheKey = (CacheKey) o; 42 | 43 | return id == cacheKey.id && key.equals(cacheKey.key); 44 | } 45 | 46 | @Override 47 | public int hashCode() 48 | { 49 | int result = (int) (id ^ (id >>> 32)); 50 | result = 31 * result + key.hashCode(); 51 | return result; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /leveldb-api/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 | 22 | /** 23 | * @author Hiram Chirino 24 | */ 25 | public interface WriteBatch 26 | extends Closeable 27 | { 28 | /** 29 | * The size of the database changes caused by this batch. 30 | *

31 | * This number is tied to implementation details, and may change across 32 | * releases. It is intended for LevelDB usage metrics. 33 | */ 34 | int getApproximateSize(); 35 | 36 | /** 37 | * Number of entries in the batch 38 | */ 39 | int size(); 40 | 41 | /** 42 | * Store the mapping key and value in the database. 43 | */ 44 | WriteBatch put(byte[] key, byte[] value); 45 | 46 | /** 47 | * If the database contains a mapping for "key", erase it. Else do nothing. 48 | */ 49 | WriteBatch delete(byte[] key); 50 | } 51 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/ILRUCache.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.concurrent.Callable; 21 | import java.util.concurrent.ExecutionException; 22 | 23 | public interface ILRUCache 24 | { 25 | /** 26 | * Get cached valued by key or load and cache loaded value. 27 | * 28 | * @param key cache key 29 | * @param loader key value loader 30 | * @return loaded/saved value 31 | * @throws ExecutionException if load has any exception. 32 | */ 33 | V load(final K key, Callable loader) throws ExecutionException; 34 | 35 | long getApproximateMemoryUsage(); 36 | 37 | /** 38 | * Get a value from cache if present (already loaded) 39 | * 40 | * @param key cache key 41 | * @return value if present, {@ode null} otherwise 42 | */ 43 | V getIfPresent(K key); 44 | 45 | /** 46 | * Discards all entries in the cache. 47 | */ 48 | void invalidateAll(); 49 | } 50 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/memenv/MemWritableFile.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.memenv; 19 | 20 | import org.iq80.leveldb.env.WritableFile; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import java.io.IOException; 24 | import java.nio.channels.ClosedChannelException; 25 | 26 | class MemWritableFile implements WritableFile 27 | { 28 | private final FileState fileState; 29 | private boolean closed; 30 | 31 | public MemWritableFile(FileState fileState) 32 | { 33 | this.fileState = fileState; 34 | } 35 | 36 | @Override 37 | public void append(Slice data) throws IOException 38 | { 39 | if (closed) { 40 | throw new ClosedChannelException(); 41 | } 42 | fileState.append(data); 43 | } 44 | 45 | @Override 46 | public void force() throws IOException 47 | { 48 | } 49 | 50 | @Override 51 | public void close() throws IOException 52 | { 53 | closed = true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /leveldb-api/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 | * A range of keys as of {@code [start, limit) } 22 | * @author Hiram Chirino 23 | */ 24 | public class Range 25 | { 26 | private final byte[] start; 27 | private final byte[] limit; 28 | 29 | /** 30 | * Included in the range 31 | */ 32 | public byte[] limit() 33 | { 34 | return limit; 35 | } 36 | 37 | /** 38 | * Not included in the range 39 | */ 40 | public byte[] start() 41 | { 42 | return start; 43 | } 44 | 45 | /** 46 | * @param start key included in the range 47 | * @param limit key not included in the range 48 | */ 49 | public Range(byte[] start, byte[] limit) 50 | { 51 | Options.checkArgNotNull(start, "start"); 52 | Options.checkArgNotNull(limit, "limit"); 53 | this.limit = limit; 54 | this.start = start; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/InsertIntoHandler.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.Slices; 22 | 23 | import static org.iq80.leveldb.impl.ValueType.DELETION; 24 | import static org.iq80.leveldb.impl.ValueType.VALUE; 25 | 26 | final class InsertIntoHandler 27 | implements WriteBatchImpl.Handler 28 | { 29 | private long sequence; 30 | private final MemTable memTable; 31 | 32 | public InsertIntoHandler(MemTable memTable, long sequenceBegin) 33 | { 34 | this.memTable = memTable; 35 | this.sequence = sequenceBegin; 36 | } 37 | 38 | @Override 39 | public void put(Slice key, Slice value) 40 | { 41 | memTable.add(sequence++, VALUE, key.copySlice(), value.copySlice()); 42 | } 43 | 44 | @Override 45 | public void delete(Slice key) 46 | { 47 | memTable.add(sequence++, DELETION, key.copySlice(), Slices.EMPTY_SLICE); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /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 | { 22 | private int seekFileLevel = -1; 23 | private FileMetaData seekFile; 24 | 25 | ReadStats() 26 | { 27 | } 28 | 29 | ReadStats(int seekFileLevel, FileMetaData seekFile) 30 | { 31 | this.seekFileLevel = seekFileLevel; 32 | this.seekFile = seekFile; 33 | } 34 | 35 | public void clear() 36 | { 37 | seekFileLevel = -1; 38 | seekFile = null; 39 | } 40 | 41 | public int getSeekFileLevel() 42 | { 43 | return seekFileLevel; 44 | } 45 | 46 | public void setSeekFileLevel(int seekFileLevel) 47 | { 48 | this.seekFileLevel = seekFileLevel; 49 | } 50 | 51 | public FileMetaData getSeekFile() 52 | { 53 | return seekFile; 54 | } 55 | 56 | public void setSeekFile(FileMetaData seekFile) 57 | { 58 | this.seekFile = seekFile; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/impl/WriteBatchImplTest.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 static org.testng.Assert.assertTrue; 24 | 25 | public class WriteBatchImplTest 26 | { 27 | @Test 28 | public void testApproximateSize() 29 | { 30 | WriteBatchImpl batch = new WriteBatchImpl(); 31 | int emptySize = batch.getApproximateSize(); 32 | 33 | batch.put(slice("foo"), slice("bar")); 34 | int oneKeySize = batch.getApproximateSize(); 35 | assertTrue(emptySize < oneKeySize); 36 | 37 | batch.put(slice("baz"), slice("boo")); 38 | int twoKeysSize = batch.getApproximateSize(); 39 | assertTrue(oneKeySize < twoKeysSize); 40 | 41 | batch.delete(slice("box")); 42 | int postDeleteSize = batch.getApproximateSize(); 43 | assertTrue(twoKeysSize < postDeleteSize); 44 | } 45 | 46 | private static Slice slice(String txt) 47 | { 48 | return new Slice(txt.getBytes()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /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 org.iq80.leveldb.table.UserComparator; 21 | 22 | import java.util.Comparator; 23 | 24 | public class InternalKeyComparator 25 | implements Comparator 26 | { 27 | private final UserComparator userComparator; 28 | 29 | public InternalKeyComparator(UserComparator userComparator) 30 | { 31 | this.userComparator = userComparator; 32 | } 33 | 34 | public UserComparator getUserComparator() 35 | { 36 | return userComparator; 37 | } 38 | 39 | public String name() 40 | { 41 | return this.userComparator.name(); 42 | } 43 | 44 | @Override 45 | public int compare(InternalKey left, InternalKey right) 46 | { 47 | int result = userComparator.compare(left.getUserKey(), right.getUserKey()); 48 | if (result != 0) { 49 | return result; 50 | } 51 | 52 | return Long.compare(right.getSequenceNumber(), left.getSequenceNumber()); // reverse sorted version numbers 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /leveldb-api/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 | import java.io.Closeable; 21 | import java.io.IOException; 22 | 23 | /** 24 | * An interface for writing log messages. 25 | * 26 | * @author Hiram Chirino 27 | */ 28 | public interface Logger extends Closeable 29 | { 30 | void log(String message); 31 | 32 | /** 33 | * Substitutes each {@code %s} in {@code template} with an argument. Arguments without place holder will 34 | * be placed at the end of template. 35 | *

36 | * This is a default method to avoid incompatibilities with older logger interface. 37 | * 38 | * @param template a non-null template string containing 0 or more {@code %s} placeholders. 39 | * @param args the arguments to be substituted into the message template. 40 | */ 41 | default void log(String template, Object... args) 42 | { 43 | log(String.format(template, args)); 44 | } 45 | 46 | @Override 47 | default void close() throws IOException 48 | { 49 | //default to be compatible with older interface 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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.google.common.base.Preconditions.checkArgument; 21 | import static java.util.Objects.requireNonNull; 22 | 23 | public final class SequenceNumber 24 | { 25 | // We leave eight bits empty at the bottom so a type and sequence# 26 | // can be packed together into 64-bits. 27 | public static final long MAX_SEQUENCE_NUMBER = ((0x1L << 56) - 1); 28 | 29 | private SequenceNumber() 30 | { 31 | } 32 | 33 | public static long packSequenceAndValueType(long sequence, ValueType valueType) 34 | { 35 | checkArgument(sequence <= MAX_SEQUENCE_NUMBER, "Sequence number is greater than MAX_SEQUENCE_NUMBER"); 36 | requireNonNull(valueType, "valueType is null"); 37 | 38 | return (sequence << 8) | valueType.getPersistentId(); 39 | } 40 | 41 | public static ValueType unpackValueType(long num) 42 | { 43 | return ValueType.getValueTypeByPersistentId((byte) num); 44 | } 45 | 46 | public static long unpackSequenceNumber(long num) 47 | { 48 | return num >>> 8; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /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.google.common.base.Preconditions.checkArgument; 21 | 22 | public enum LogChunkType 23 | { 24 | ZERO_TYPE(0), 25 | FULL(1), 26 | FIRST(2), 27 | MIDDLE(3), 28 | LAST(4), 29 | EOF, 30 | BAD_CHUNK, 31 | UNKNOWN; 32 | 33 | public static LogChunkType getLogChunkTypeByPersistentId(int persistentId) 34 | { 35 | for (LogChunkType logChunkType : LogChunkType.values()) { 36 | if (logChunkType.persistentId != null && logChunkType.persistentId == persistentId) { 37 | return logChunkType; 38 | } 39 | } 40 | return UNKNOWN; 41 | } 42 | 43 | private final Integer persistentId; 44 | 45 | LogChunkType() 46 | { 47 | this.persistentId = null; 48 | } 49 | 50 | LogChunkType(int persistentId) 51 | { 52 | this.persistentId = persistentId; 53 | } 54 | 55 | public int getPersistentId() 56 | { 57 | checkArgument(persistentId != null, "%s is not a persistent chunk type", name()); 58 | return persistentId; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Hive Games takes the security of our software products and services seriously, which includes all source code 4 | repositories managed through our GitHub organizations. 5 | 6 | If you believe you have found a security vulnerability in any Hive Games repository which follows the MITRE.org 7 | definition of “a weakness in the computational logic (e.g., code) found in software and hardware components that, when 8 | exploited, results in a negative impact to confidentiality, integrity, OR availability. Mitigation of the 9 | vulnerabilities in this context typically involves coding changes but could also include specification changes or even 10 | specification deprecations (e.g., removal of affected protocols or functionality in their entirety).” MITRE.org CNA 11 | Rules 7.1, please report it to us as described below. 12 | 13 | ## Reporting Security Issues 14 | 15 | **Please do not report security vulnerabilities through public GitHub issues.** 16 | 17 | Instead, please send email to [secure@hivemc.com](mailto:secure@hivemc.com). 18 | 19 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we 20 | received your original message. 21 | 22 | Please include the requested information listed below (as much as you can provide) to help us better understand the 23 | nature and scope of the possible issue: 24 | 25 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 26 | * Full paths of source file(s) related to the manifestation of the issue 27 | * The location of the affected source code (tag/branch/commit or direct URL) 28 | * Any special configuration required to reproduce the issue 29 | * Step-by-step instructions to reproduce the issue 30 | * Proof-of-concept or exploit code (if possible) 31 | * Impact of the issue, including how an attacker might exploit the issue 32 | 33 | This information will help us triage your report more quickly. 34 | 35 | ## Preferred Languages 36 | 37 | We prefer all communications to be in English. 38 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/RestartPositions.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 static com.google.common.base.Preconditions.checkArgument; 23 | import static com.google.common.base.Preconditions.checkPositionIndex; 24 | import static java.util.Objects.requireNonNull; 25 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_INT; 26 | 27 | final class RestartPositions 28 | { 29 | private final Slice restartPositions; 30 | private final int size; 31 | 32 | RestartPositions(Slice restartPositions) 33 | { 34 | requireNonNull(restartPositions, "restartPositions is null"); 35 | checkArgument(restartPositions.length() % SIZE_OF_INT == 0, "restartPositions.readableBytes() must be a multiple of %s", SIZE_OF_INT); 36 | this.restartPositions = restartPositions; 37 | this.size = restartPositions.length() / SIZE_OF_INT; 38 | } 39 | 40 | public int get(int index) 41 | { 42 | checkPositionIndex(index, size, "index out of range"); 43 | return restartPositions.getInt(index * SIZE_OF_INT); 44 | } 45 | 46 | public boolean isEmpty() 47 | { 48 | return size == 0; 49 | } 50 | 51 | public int size() 52 | { 53 | return size; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /leveldb-api/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 | { 28 | /** 29 | * Open/Create a new Database using provided "options" to configure DB 30 | * behavior. 31 | * 32 | * @param path DB root folder 33 | * @param options DB options 34 | * @return a new DB instance 35 | * @throws IOException if unable to open/read DB or preconditions failed 36 | */ 37 | DB open(File path, Options options) 38 | throws IOException; 39 | 40 | /** 41 | * Destroy a database, delete DB files and root directory 42 | * @param path DB root folder 43 | * @param options options used to open DB 44 | * @throws IOException if failed to destruct DB 45 | */ 46 | void destroy(File path, Options options) 47 | throws IOException; 48 | 49 | /** 50 | * Try to repair a corrupted DB or not closed properly. 51 | * @param path DB root directory 52 | * @param options DB options 53 | * @throws IOException if failed to open/recover DB 54 | */ 55 | void repair(File path, Options options) 56 | throws IOException; 57 | } 58 | -------------------------------------------------------------------------------- /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 java.util.Objects.requireNonNull; 23 | 24 | public class LookupResult 25 | { 26 | public static LookupResult ok(LookupKey key, Slice value) 27 | { 28 | return new LookupResult(key, value, false); 29 | } 30 | 31 | public static LookupResult deleted(LookupKey key) 32 | { 33 | return new LookupResult(key, null, true); 34 | } 35 | 36 | private final LookupKey key; 37 | private final Slice value; 38 | private final boolean deleted; 39 | 40 | private LookupResult(LookupKey key, Slice value, boolean deleted) 41 | { 42 | requireNonNull(key, "key is null"); 43 | this.key = key; 44 | if (value != null) { 45 | this.value = value.slice(); 46 | } 47 | else { 48 | this.value = null; 49 | } 50 | this.deleted = deleted; 51 | } 52 | 53 | public LookupKey getKey() 54 | { 55 | return key; 56 | } 57 | 58 | public Slice getValue() 59 | { 60 | if (value == null) { 61 | return null; 62 | } 63 | return value; 64 | } 65 | 66 | public boolean isDeleted() 67 | { 68 | return deleted; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /leveldb-api/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 | /** 21 | * DB contents are stored in a set of blocks, each of which holds a 22 | * sequence of key,value pairs. Each block may be compressed before 23 | * being stored in a file. The following enum describes which 24 | * compression method (if any) is used to compress a block. 25 | */ 26 | public enum CompressionType 27 | { 28 | // NOTE: do not change the values of existing entries, as these are 29 | // part of the persistent format on disk. 30 | NONE(0x00), 31 | SNAPPY(0x01), 32 | // MCPE Compression Types 33 | ZLIB(0x02), 34 | ZLIB_RAW(0x04); 35 | 36 | public static CompressionType getCompressionTypeByPersistentId(int persistentId) 37 | { 38 | for (CompressionType compressionType : CompressionType.values()) { 39 | if (compressionType.persistentId == persistentId) { 40 | return compressionType; 41 | } 42 | } 43 | throw new IllegalArgumentException("Unknown persistentId " + persistentId); 44 | } 45 | 46 | private final int persistentId; 47 | 48 | CompressionType(int persistentId) 49 | { 50 | this.persistentId = persistentId; 51 | } 52 | 53 | public int persistentId() 54 | { 55 | return persistentId; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/env/SequentialFile.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.env; 19 | 20 | import org.iq80.leveldb.util.SliceOutput; 21 | 22 | import java.io.Closeable; 23 | import java.io.IOException; 24 | 25 | public interface SequentialFile extends Closeable 26 | { 27 | /** 28 | * Skips over and discards n bytes of data from the 29 | * input stream. 30 | * 31 | * @param n the number of bytes to be skipped. 32 | * @throws IOException if n is negative, if the stream does not 33 | * support seek, or if an I/O error occurs. 34 | */ 35 | void skip(long n) throws IOException; 36 | 37 | /** 38 | * Read up to "atMost" bytes from the file. 39 | * 40 | * @param atMost the maximum number of bytes to read. 41 | * @param destination data destination 42 | * @return the total number of bytes read into the destination, or 43 | * -1 if there is no more data because the end of 44 | * the stream has been reached. 45 | * @throws IOException If the first byte cannot be read for any reason 46 | * other than end of file, or if the input stream has been closed, or if 47 | * some other I/O error occurs. 48 | */ 49 | int read(int atMost, SliceOutput destination) throws IOException; 50 | } 51 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/memenv/MemRandomInputFile.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.memenv; 19 | 20 | import org.iq80.leveldb.env.File; 21 | import org.iq80.leveldb.env.RandomInputFile; 22 | 23 | import java.io.IOException; 24 | import java.nio.ByteBuffer; 25 | import java.nio.channels.ClosedChannelException; 26 | 27 | class MemRandomInputFile implements RandomInputFile 28 | { 29 | private final File file; 30 | private final FileState fileState; 31 | private boolean closed; 32 | 33 | public MemRandomInputFile(File file, FileState fileState) 34 | { 35 | this.file = file; 36 | this.fileState = fileState; 37 | closed = false; 38 | } 39 | 40 | @Override 41 | public long size() 42 | { 43 | return file.length(); 44 | } 45 | 46 | @Override 47 | public ByteBuffer read(long offset, int length) throws IOException 48 | { 49 | if (closed) { 50 | throw new ClosedChannelException(); 51 | } 52 | byte[] read = fileState.read(offset, length); 53 | if (read == null) { 54 | throw new IOException("Could not read all the data"); 55 | } 56 | // read is already a copy 57 | return ByteBuffer.wrap(read); 58 | } 59 | 60 | @Override 61 | public void close() throws IOException 62 | { 63 | closed = true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/KeyMatchingLookup.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 | 19 | package org.iq80.leveldb.impl; 20 | 21 | import org.iq80.leveldb.table.KeyValueFunction; 22 | import org.iq80.leveldb.util.Slice; 23 | 24 | import static com.google.common.base.Preconditions.checkState; 25 | import static org.iq80.leveldb.impl.ValueType.VALUE; 26 | 27 | /** 28 | * @author Honore Vasconcelos 29 | */ 30 | public class KeyMatchingLookup implements KeyValueFunction 31 | { 32 | private LookupKey key; 33 | 34 | KeyMatchingLookup(LookupKey key) 35 | { 36 | this.key = key; 37 | } 38 | 39 | @Override 40 | public LookupResult apply(Slice internalKey1, Slice value) 41 | { 42 | // parse the key in the block 43 | checkState(internalKey1 != null, "Corrupt key for %s", key); 44 | 45 | final InternalKey internalKey = new InternalKey(internalKey1); 46 | 47 | // if this is a value key (not a delete) and the keys match, return the value 48 | if (key.getUserKey().equals(internalKey.getUserKey())) { 49 | if (internalKey.getValueType() == ValueType.DELETION) { 50 | return LookupResult.deleted(key); 51 | } 52 | else if (internalKey.getValueType() == VALUE) { 53 | return LookupResult.ok(key, value); 54 | } 55 | } 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/fileenv/SequentialFileImpl.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.fileenv; 19 | 20 | import org.iq80.leveldb.env.SequentialFile; 21 | import org.iq80.leveldb.util.SliceOutput; 22 | 23 | import java.io.File; 24 | import java.io.FileInputStream; 25 | import java.io.IOException; 26 | 27 | import static com.google.common.base.Preconditions.checkState; 28 | 29 | class SequentialFileImpl implements SequentialFile 30 | { 31 | private final FileInputStream inputStream; 32 | 33 | private SequentialFileImpl(FileInputStream inputStream) 34 | { 35 | this.inputStream = inputStream; 36 | } 37 | 38 | public static SequentialFile open(File file) throws IOException 39 | { 40 | return new SequentialFileImpl(new FileInputStream(file)); 41 | } 42 | 43 | @Override 44 | public void skip(long n) throws IOException 45 | { 46 | checkState(n >= 0, "n must be positive"); 47 | if (inputStream.skip(n) != n) { 48 | throw new IOException(inputStream + " as not enough bytes to skip"); 49 | } 50 | } 51 | 52 | @Override 53 | public int read(int atMost, SliceOutput destination) throws IOException 54 | { 55 | return destination.writeBytes(inputStream, atMost); 56 | } 57 | 58 | @Override 59 | public void close() throws IOException 60 | { 61 | inputStream.close(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /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 | import org.iq80.leveldb.Logger; 21 | 22 | public final class LogMonitors 23 | { 24 | public static LogMonitor throwExceptionMonitor() 25 | { 26 | return new LogMonitor() 27 | { 28 | @Override 29 | public void corruption(long bytes, String reason) 30 | { 31 | throw new RuntimeException(String.format("corruption of %s bytes: %s", bytes, reason)); 32 | } 33 | 34 | @Override 35 | public void corruption(long bytes, Throwable reason) 36 | { 37 | throw new RuntimeException(String.format("corruption of %s bytes", bytes), reason); 38 | } 39 | }; 40 | } 41 | 42 | public static LogMonitor logMonitor(Logger logger) 43 | { 44 | return new LogMonitor() 45 | { 46 | @Override 47 | public void corruption(long bytes, String reason) 48 | { 49 | logger.log("corruption of %s bytes: %s", bytes, reason); 50 | } 51 | 52 | @Override 53 | public void corruption(long bytes, Throwable reason) 54 | { 55 | logger.log("corruption of %s bytes. %s", bytes, reason); 56 | } 57 | }; 58 | } 59 | 60 | private LogMonitors() 61 | { 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/env/File.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.env; 19 | 20 | import java.util.List; 21 | 22 | public interface File 23 | { 24 | /** 25 | * Resolve the given path against this path. 26 | * 27 | * @param other the path to resolve against this path 28 | * @return the resulting path 29 | */ 30 | File child(String other); 31 | 32 | /** 33 | * Creates the directory named by this file, including any 34 | * necessary but nonexistent parent directories. 35 | * 36 | * @return {@code true} if and only if the directory was created, 37 | * along with all necessary parent directories; {@code false} 38 | * otherwise 39 | */ 40 | boolean mkdirs(); 41 | 42 | String getName(); 43 | 44 | File getParentFile(); 45 | 46 | String getPath(); 47 | 48 | boolean canRead(); 49 | 50 | boolean exists(); 51 | 52 | boolean isDirectory(); 53 | 54 | boolean isFile(); 55 | 56 | /** 57 | * @return File size or {@code 0L} if file does not exist 58 | */ 59 | long length(); 60 | 61 | boolean delete(); 62 | 63 | List listFiles(); 64 | 65 | boolean renameTo(File dest); 66 | 67 | /** 68 | * Delete this file and all its contained files and directories. 69 | * @return {@code true} if all content and this file where deleted, {@code false} 70 | * otherwise 71 | */ 72 | boolean deleteRecursively(); 73 | } 74 | -------------------------------------------------------------------------------- /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 org.iq80.leveldb.env.Env; 21 | import org.iq80.leveldb.util.PureJavaCrc32C; 22 | import org.iq80.leveldb.util.Slice; 23 | import org.iq80.leveldb.env.WritableFile; 24 | 25 | import org.iq80.leveldb.env.File; 26 | import java.io.IOException; 27 | 28 | public final class Logs 29 | { 30 | private Logs() 31 | { 32 | } 33 | 34 | public static LogWriter createLogWriter(File file, long fileNumber, Env env) throws IOException 35 | { 36 | return LogWriter.createWriter(fileNumber, env.newWritableFile(file)); 37 | } 38 | 39 | public static LogWriter createLogWriter(long fileNumber, WritableFile writableFile, long destinationLength) throws IOException 40 | { 41 | return LogWriter.createWriter(fileNumber, writableFile, destinationLength); 42 | } 43 | 44 | public static int getChunkChecksum(int chunkTypeId, Slice slice) 45 | { 46 | return getChunkChecksum(chunkTypeId, slice.getRawArray(), slice.getRawOffset(), slice.length()); 47 | } 48 | 49 | public static int getChunkChecksum(int chunkTypeId, byte[] buffer, int offset, int length) 50 | { 51 | // Compute the crc of the record type and the payload. 52 | PureJavaCrc32C crc32C = new PureJavaCrc32C(); 53 | crc32C.update(chunkTypeId); 54 | crc32C.update(buffer, offset, length); 55 | return crc32C.getMaskedValue(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /leveldb-api/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 | /** 31 | * Repositions the iterator so the key of the next BlockElement 32 | * returned greater than or equal to the specified targetKey. 33 | */ 34 | void seek(byte[] key); 35 | 36 | /** 37 | * Repositions the iterator so is is at the beginning of the Database. 38 | */ 39 | void seekToFirst(); 40 | 41 | /** 42 | * Returns the next element in the iteration, without advancing the iteration. 43 | */ 44 | Map.Entry peekNext(); 45 | 46 | /** 47 | * @return true if there is a previous entry in the iteration. 48 | */ 49 | boolean hasPrev(); 50 | 51 | /** 52 | * @return the previous element in the iteration and rewinds the iteration. 53 | */ 54 | Map.Entry prev(); 55 | 56 | /** 57 | * @return the previous element in the iteration, without rewinding the iteration. 58 | */ 59 | Map.Entry peekPrev(); 60 | 61 | /** 62 | * Repositions the iterator so it is at the end of of the Database. 63 | */ 64 | void seekToLast(); 65 | 66 | @Override 67 | void close(); 68 | } 69 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/impl/VersionEditTest.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 static org.iq80.leveldb.util.TestUtils.asciiToSlice; 24 | import static org.testng.Assert.assertEquals; 25 | 26 | public class VersionEditTest 27 | { 28 | @Test 29 | public void testEncodeDecode() throws Exception 30 | { 31 | long kBig = 1L << 50; 32 | 33 | VersionEdit edit = new VersionEdit(); 34 | for (int i = 0; i < 4; i++) { 35 | testEncodeDecode(edit); 36 | edit.addFile(3, kBig + 300 + i, kBig + 400 + i, 37 | new InternalKey(asciiToSlice("foo"), kBig + 500 + i, ValueType.VALUE), 38 | new InternalKey(asciiToSlice("zoo"), kBig + 600 + i, ValueType.DELETION)); 39 | edit.deleteFile(4, kBig + 700 + i); 40 | edit.setCompactPointer(i, new InternalKey(asciiToSlice("x"), kBig + 900 + i, ValueType.VALUE)); 41 | } 42 | 43 | edit.setComparatorName("foo"); 44 | edit.setLogNumber(kBig + 100); 45 | edit.setNextFileNumber(kBig + 200); 46 | edit.setLastSequenceNumber(kBig + 1000); 47 | testEncodeDecode(edit); 48 | } 49 | 50 | void testEncodeDecode(VersionEdit edit) 51 | { 52 | Slice encoded = edit.encode(); 53 | VersionEdit parsed = new VersionEdit(encoded); 54 | Slice encoded2 = parsed.encode(); 55 | assertEquals(encoded, encoded2); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/fileenv/UnbufferedWritableFile.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.fileenv; 19 | 20 | import org.iq80.leveldb.util.Slice; 21 | import org.iq80.leveldb.env.WritableFile; 22 | 23 | import java.io.File; 24 | import java.io.FileNotFoundException; 25 | import java.io.FileOutputStream; 26 | import java.io.IOException; 27 | import java.nio.channels.FileChannel; 28 | 29 | /** 30 | * @author Honore Vasconcelos 31 | */ 32 | class UnbufferedWritableFile implements WritableFile 33 | { 34 | private final File file; 35 | private final FileChannel channel; 36 | 37 | private UnbufferedWritableFile(File file, FileChannel channel) 38 | { 39 | this.file = file; 40 | this.channel = channel; 41 | } 42 | 43 | public static WritableFile open(File file, boolean append) throws FileNotFoundException 44 | { 45 | return new UnbufferedWritableFile(file, new FileOutputStream(file, append).getChannel()); 46 | } 47 | 48 | @Override 49 | public void append(Slice data) throws IOException 50 | { 51 | channel.write(data.toByteBuffer()); 52 | } 53 | 54 | @Override 55 | public void force() throws IOException 56 | { 57 | channel.force(false); 58 | } 59 | 60 | @Override 61 | public void close() throws IOException 62 | { 63 | channel.close(); 64 | } 65 | 66 | @Override 67 | public String toString() 68 | { 69 | return "UnbufferedWritableFile{" + 70 | "file=" + file + 71 | '}'; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /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 | import static java.util.Objects.requireNonNull; 24 | 25 | public class CustomUserComparator 26 | implements UserComparator 27 | { 28 | private final DBComparator comparator; 29 | 30 | public CustomUserComparator(DBComparator comparator) 31 | { 32 | requireNonNull(comparator.name(), "User Comparator name can't be null"); 33 | this.comparator = comparator; 34 | } 35 | 36 | @Override 37 | public String name() 38 | { 39 | return comparator.name(); 40 | } 41 | 42 | @Override 43 | public Slice findShortestSeparator(Slice start, Slice limit) 44 | { 45 | byte[] shortestSeparator = comparator.findShortestSeparator(start.getBytes(), limit.getBytes()); 46 | requireNonNull(shortestSeparator, "User comparator returned null from findShortestSeparator()"); 47 | return new Slice(shortestSeparator); 48 | } 49 | 50 | @Override 51 | public Slice findShortSuccessor(Slice key) 52 | { 53 | byte[] shortSuccessor = comparator.findShortSuccessor(key.getBytes()); 54 | requireNonNull(comparator, "User comparator returned null from findShortSuccessor()"); 55 | return new Slice(shortSuccessor); 56 | } 57 | 58 | @Override 59 | public int compare(Slice o1, Slice o2) 60 | { 61 | return comparator.compare(o1.getBytes(), o2.getBytes()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /leveldb-api/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 | { 28 | /** 29 | * The name of the comparator. Used to check for comparator 30 | * mismatches (i.e., a DB created with one comparator is 31 | * accessed using a different comparator. 32 | *

33 | * The client of this package should switch to a new name whenever 34 | * the comparator implementation changes in a way that will cause 35 | * the relative ordering of any two keys to change. 36 | *

fileState.length()) { 41 | throw new IOException("File position " + index + " is greater than file size"); 42 | } 43 | long available = fileState.length() - index; 44 | if (n > available) { 45 | n = available; 46 | } 47 | index += n; 48 | } 49 | 50 | @Override 51 | public int read(int atMost, SliceOutput destination) throws IOException 52 | { 53 | if (closed) { 54 | throw new ClosedChannelException(); 55 | } 56 | byte[] read = fileState.read(index, atMost); 57 | if (read != null) { 58 | index += read.length; 59 | destination.writeBytes(read); 60 | return read.length; 61 | } 62 | return -1; 63 | } 64 | 65 | @Override 66 | public void close() throws IOException 67 | { 68 | closed = true; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/util/HashTest.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 | /** 25 | * @author Honore Vasconcelos 26 | */ 27 | public class HashTest 28 | { 29 | @Test 30 | public void testSignedUnsignedTrue() throws Exception 31 | { 32 | byte[] data1 = {0x62}; 33 | byte[] data2 = {(byte) 0xc3, (byte) 0x97}; 34 | byte[] data3 = {(byte) 0xe2, (byte) 0x99, (byte) 0xa5}; 35 | byte[] data4 = {(byte) 0xe1, (byte) 0x80, (byte) 0xb9, 0x32}; 36 | byte[] data5 = { 37 | 0x01, (byte) 0xc0, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 41 | 0x14, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x04, 0x00, 43 | 0x00, 0x00, 0x00, 0x14, 44 | 0x00, 0x00, 0x00, 0x18, 45 | 0x28, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 47 | 0x02, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 49 | }; 50 | assertEquals(Hash.hash(new byte[0], 0xbc9f1d34), 0xbc9f1d34); 51 | assertEquals(Hash.hash(data1, 0xbc9f1d34), 0xef1345c4); 52 | assertEquals(Hash.hash(data2, 0xbc9f1d34), 0x5b663814); 53 | assertEquals(Hash.hash(data3, 0xbc9f1d34), 0x323c078f); 54 | assertEquals(Hash.hash(data4, 0xbc9f1d34), 0xed21633a); 55 | assertEquals(Hash.hash(data5, 0x12345678), 0xf333dabb); 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/fileenv/FileLogger.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.fileenv; 19 | 20 | import org.iq80.leveldb.Logger; 21 | import org.iq80.leveldb.util.LogMessageFormatter; 22 | 23 | import java.io.File; 24 | import java.io.FileOutputStream; 25 | import java.io.IOException; 26 | import java.io.OutputStream; 27 | import java.io.PrintStream; 28 | import java.time.LocalDateTime; 29 | import java.util.function.Supplier; 30 | 31 | class FileLogger 32 | implements Logger 33 | { 34 | private final PrintStream ps; 35 | private final LogMessageFormatter formatter; 36 | 37 | private FileLogger(PrintStream ps, LogMessageFormatter formatter) 38 | { 39 | this.ps = ps; 40 | this.formatter = formatter; 41 | } 42 | 43 | public static Logger createLogger(OutputStream outputStream, Supplier clock) 44 | { 45 | return new FileLogger(new PrintStream(outputStream), new LogMessageFormatter(clock)); 46 | } 47 | 48 | public static Logger createFileLogger(File loggerFile) throws IOException 49 | { 50 | return createLogger(new FileOutputStream(loggerFile), LocalDateTime::now); 51 | } 52 | 53 | @Override 54 | public void log(String template, Object... args) 55 | { 56 | log2(formatter.format(template, args)); 57 | } 58 | 59 | @Override 60 | public void log(String message) 61 | { 62 | log2(formatter.format(message)); 63 | } 64 | 65 | private void log2(String message) 66 | { 67 | ps.println(message); 68 | } 69 | 70 | @Override 71 | public void close() throws IOException 72 | { 73 | ps.close(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/FilterPolicy.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 | 19 | package org.iq80.leveldb.table; 20 | 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import java.util.List; 24 | 25 | /** 26 | * A database can be configured with a custom FilterPolicy object. 27 | * This object is responsible for creating a small filter from a set 28 | * of keys. These filters are stored in leveldb and are consulted 29 | * automatically by leveldb to decide whether or not to read some 30 | * information from disk. In many cases, a filter can cut down the 31 | * number of disk seeks form a handful to a single disk seek per 32 | * DB::Get() call. 33 | *

34 | * Most people will want to use the builtin bloom filter support (see 35 | * NewBloomFilterPolicy() below). 36 | * 37 | * @author Honore Vasconcelos 38 | */ 39 | public interface FilterPolicy extends org.iq80.leveldb.XFilterPolicy 40 | { 41 | String name(); 42 | 43 | /** 44 | * Append a filter that summarizes keys[0,n-1] to *dst. 45 | * 46 | * @param keys keys[0,n-1] contains a list of keys (potentially with duplicates) 47 | * that are ordered according to the user supplied comparator. 48 | */ 49 | byte[] createFilter(List keys); 50 | 51 | /** 52 | * "filter" contains the data appended by a preceding call to 53 | * CreateFilter() on this class. This method must return true if 54 | * the key was in the list of keys passed to CreateFilter(). 55 | * This method may return true or false if the key was not on the 56 | * list, but it should aim to return false with a high probability. 57 | */ 58 | boolean keyMayMatch(Slice key, Slice filter); 59 | } 60 | -------------------------------------------------------------------------------- /leveldb-api/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 | /** 21 | * Options that control read operations 22 | */ 23 | public class ReadOptions 24 | { 25 | private boolean verifyChecksums; 26 | private boolean fillCache = true; 27 | private Snapshot snapshot; 28 | 29 | public Snapshot snapshot() 30 | { 31 | return snapshot; 32 | } 33 | 34 | /** 35 | * If "snapshot" is non-null, read as of the supplied snapshot 36 | * (which must belong to the DB that is being read and which must 37 | * not have been closed). If "snapshot" is null, use an implicit 38 | * snapshot of the state at the beginning of this read operation. 39 | */ 40 | public ReadOptions snapshot(Snapshot snapshot) 41 | { 42 | this.snapshot = snapshot; 43 | return this; 44 | } 45 | 46 | public boolean fillCache() 47 | { 48 | return fillCache; 49 | } 50 | 51 | /** 52 | * Should the data read for this iteration be cached in memory? 53 | * Callers may wish to set this field to false for bulk scans. 54 | */ 55 | public ReadOptions fillCache(boolean fillCache) 56 | { 57 | this.fillCache = fillCache; 58 | return this; 59 | } 60 | 61 | public boolean verifyChecksums() 62 | { 63 | return verifyChecksums; 64 | } 65 | 66 | /** 67 | * If true, all data read from underlying storage will be 68 | * verified against corresponding checksums. 69 | */ 70 | public ReadOptions verifyChecksums(boolean verifyChecksums) 71 | { 72 | this.verifyChecksums = verifyChecksums; 73 | return this; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /leveldb-api/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 | /** 21 | * Options that control write operations 22 | */ 23 | public class WriteOptions 24 | { 25 | private boolean sync; 26 | private boolean snapshot; 27 | 28 | /** 29 | * If true, the write will be flushed from the operating system 30 | * buffer cache (by calling WritableFile::Sync()) before the write 31 | * is considered complete. If this flag is true, writes will be 32 | * slower. 33 | *

34 | * If this flag is false, and the machine crashes, some recent 35 | * writes may be lost. Note that if it is just the process that 36 | * crashes (i.e., the machine does not reboot), no writes will be 37 | * lost even if sync==false. 38 | *

39 | * In other words, a DB write with sync==false has similar 40 | * crash semantics as the "write()" system call. A DB write 41 | * with sync==true has similar crash semantics to a "write()" 42 | * system call followed by "fsync()". 43 | *

44 | * In java Implementation if process crash 45 | * Default: false 46 | **/ 47 | public boolean sync() 48 | { 49 | return sync; 50 | } 51 | 52 | public WriteOptions sync(boolean sync) 53 | { 54 | this.sync = sync; 55 | return this; 56 | } 57 | 58 | /** 59 | * If "snapshot" is true, take a snapshot at the end of this write operation 60 | */ 61 | public boolean snapshot() 62 | { 63 | return snapshot; 64 | } 65 | 66 | public WriteOptions snapshot(boolean snapshot) 67 | { 68 | this.snapshot = snapshot; 69 | return this; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /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 | { 22 | public static final int MAJOR_VERSION = 0; 23 | public static final int MINOR_VERSION = 1; 24 | 25 | // todo this should be part of the configuration 26 | 27 | /** 28 | * Max number of levels 29 | */ 30 | public static final int NUM_LEVELS = 7; 31 | 32 | /** 33 | * Level-0 compaction is started when we hit this many files. 34 | */ 35 | public static final int L0_COMPACTION_TRIGGER = 4; 36 | 37 | /** 38 | * Soft limit on number of level-0 files. We slow down writes at this point. 39 | */ 40 | public static final int L0_SLOWDOWN_WRITES_TRIGGER = 8; 41 | 42 | /** 43 | * Maximum number of level-0 files. We stop writes at this point. 44 | */ 45 | public static final int L0_STOP_WRITES_TRIGGER = 12; 46 | 47 | /** 48 | * Maximum level to which a new compacted memtable is pushed if it 49 | * does not create overlap. We try to push to level 2 to avoid the 50 | * relatively expensive level 0=>1 compactions and to avoid some 51 | * expensive manifest file operations. We do not push all the way to 52 | * the largest level since that can generate a lot of wasted disk 53 | * space if the same key space is being repeatedly overwritten. 54 | */ 55 | public static final int MAX_MEM_COMPACT_LEVEL = 2; 56 | 57 | /** 58 | * Approximate gap in bytes between samples of data read during iteration. 59 | */ 60 | public static final int READ_BYTES_PERIOD = 1048576; 61 | 62 | public static final int NUM_NON_TABLE_CACHE_FILES = 10; 63 | 64 | private DbConstants() 65 | { 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /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.google.common.base.Preconditions.checkArgument; 23 | 24 | public class IntVector 25 | { 26 | private int size; 27 | private int[] values; 28 | 29 | public IntVector(int initialCapacity) 30 | { 31 | this.values = new int[initialCapacity]; 32 | } 33 | 34 | public int size() 35 | { 36 | return size; 37 | } 38 | 39 | public void clear() 40 | { 41 | size = 0; 42 | } 43 | 44 | public void add(int value) 45 | { 46 | checkArgument(size + 1 >= 0, "Invalid minLength: %s", size + 1); 47 | 48 | ensureCapacity(size + 1); 49 | 50 | values[size++] = value; 51 | } 52 | 53 | private void ensureCapacity(int minCapacity) 54 | { 55 | if (values.length >= minCapacity) { 56 | return; 57 | } 58 | 59 | int newLength = values.length; 60 | if (newLength == 0) { 61 | newLength = 1; 62 | } 63 | else { 64 | newLength <<= 1; 65 | 66 | } 67 | values = Arrays.copyOf(values, newLength); 68 | } 69 | 70 | public void write(SliceOutput sliceOutput) 71 | { 72 | for (int index = 0; index < size; index++) { 73 | sliceOutput.writeInt(values[index]); 74 | } 75 | } 76 | 77 | @Override 78 | public String toString() 79 | { 80 | StringBuilder sb = new StringBuilder(); 81 | sb.append("IntVector"); 82 | sb.append("{size=").append(size); 83 | sb.append(", values=").append(Arrays.toString(values)); 84 | sb.append('}'); 85 | return sb.toString(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/LRUCache.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 | 19 | package org.iq80.leveldb.util; 20 | 21 | import com.google.common.cache.Cache; 22 | import com.google.common.cache.CacheBuilder; 23 | import com.google.common.cache.Weigher; 24 | 25 | import java.util.concurrent.Callable; 26 | import java.util.concurrent.ExecutionException; 27 | 28 | /** 29 | * LRU cache with special weigher to count correctly Slice weight. 30 | * 31 | * @author Honore Vasconcelos 32 | */ 33 | public final class LRUCache 34 | implements ILRUCache 35 | { 36 | private final Cache cache; 37 | private final Weigher weigher; 38 | 39 | private LRUCache(int capacity, final Weigher weigher) 40 | { 41 | this.cache = CacheBuilder.newBuilder() 42 | .maximumWeight(capacity) 43 | .weigher(weigher) 44 | .concurrencyLevel(1 << 4) 45 | .build(); 46 | this.weigher = weigher; 47 | } 48 | 49 | public static ILRUCache createCache(int capacity, final Weigher weigher) 50 | { 51 | return new LRUCache<>(capacity, weigher); 52 | } 53 | 54 | public V load(final K key, Callable loader) throws ExecutionException 55 | { 56 | return cache.get(key, loader); 57 | } 58 | 59 | @Override 60 | public long getApproximateMemoryUsage() 61 | { 62 | return cache.asMap().entrySet().stream() 63 | .mapToLong(e -> weigher.weigh(e.getKey(), e.getValue())) 64 | .sum(); 65 | } 66 | 67 | @Override 68 | public V getIfPresent(K key) 69 | { 70 | return cache.getIfPresent(key); 71 | } 72 | 73 | @Override 74 | public void invalidateAll() 75 | { 76 | cache.invalidateAll(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/fileenv/FileLoggerTest.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.fileenv; 19 | 20 | import org.iq80.leveldb.Logger; 21 | import org.testng.annotations.Test; 22 | 23 | import java.io.ByteArrayOutputStream; 24 | import java.io.IOException; 25 | import java.time.LocalDateTime; 26 | import java.time.temporal.ChronoUnit; 27 | import java.util.function.Supplier; 28 | 29 | import static org.testng.Assert.assertEquals; 30 | 31 | public class FileLoggerTest 32 | { 33 | @Test 34 | public void testFormatting() throws IOException 35 | { 36 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 37 | LocalDateTime start = LocalDateTime.now(); 38 | Logger fileLogger = FileLogger.createLogger(outputStream, new LocalDateTimeSupplier(start)); 39 | fileLogger.log("a bc "); 40 | fileLogger.log("without place", "arg1", "arg2"); 41 | fileLogger.log("- %s -", "abc"); 42 | fileLogger.close(); 43 | LocalDateTimeSupplier d = new LocalDateTimeSupplier(start); 44 | StringBuilder s = new StringBuilder(); 45 | s.append(d.get()).append(' ').append("a bc ").append(System.lineSeparator()); 46 | s.append(d.get()).append(' ').append("without place [arg1, arg2]").append(System.lineSeparator()); 47 | s.append(d.get()).append(' ').append("- abc -").append(System.lineSeparator()); 48 | 49 | assertEquals(new String(outputStream.toByteArray()), s.toString()); 50 | } 51 | 52 | private static class LocalDateTimeSupplier implements Supplier 53 | { 54 | LocalDateTime now; 55 | 56 | public LocalDateTimeSupplier(LocalDateTime start) 57 | { 58 | now = start; 59 | } 60 | 61 | @Override 62 | public LocalDateTime get() 63 | { 64 | now = now.plus(1, ChronoUnit.SECONDS); 65 | return now; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/impl/InternalKeyTest.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.Slices; 22 | import org.testng.Assert; 23 | import org.testng.annotations.Test; 24 | 25 | import static java.nio.charset.StandardCharsets.UTF_8; 26 | import static org.testng.Assert.assertEquals; 27 | 28 | public class InternalKeyTest 29 | { 30 | @Test 31 | public void testEncodeDecode() throws Exception 32 | { 33 | String[] keys = {"", "k", "hello", "longggggggggggggggggggggg"}; 34 | long[] seq = { 35 | 1, 2, 3, 36 | (1L << 8) - 1, 1L << 8, (1L << 8) + 1, 37 | (1L << 16) - 1, 1L << 16, (1L << 16) + 1, 38 | (1L << 32) - 1, 1L << 32, (1L << 32) + 1 39 | }; 40 | for (String key : keys) { 41 | for (long s : seq) { 42 | testKey(key, s, ValueType.VALUE); 43 | testKey("hello", 1, ValueType.DELETION); 44 | } 45 | } 46 | try { 47 | InternalKey internalKey = new InternalKey(new Slice("bar".getBytes(UTF_8))); 48 | Assert.fail("value " + internalKey + " ot expected"); 49 | } 50 | catch (Exception e) { 51 | //expected 52 | } 53 | } 54 | 55 | @Test(expectedExceptions = IllegalArgumentException.class) 56 | public void testDecodeEmpty() 57 | { 58 | new InternalKey(Slices.wrappedBuffer(new byte[0])); 59 | } 60 | 61 | private void testKey(String key, long seq, ValueType valueType) 62 | { 63 | InternalKey k = new InternalKey(Slices.wrappedBuffer(key.getBytes(UTF_8)), seq, valueType); 64 | InternalKey decoded = new InternalKey(k.encode()); 65 | 66 | assertEquals(key, decoded.getUserKey().toString(UTF_8)); 67 | assertEquals(seq, decoded.getSequenceNumber()); 68 | assertEquals(valueType, decoded.getValueType()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/table/FilterBlockReader.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 | 19 | package org.iq80.leveldb.table; 20 | 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | /** 24 | * @author Honore Vasconcelos 25 | */ 26 | final class FilterBlockReader 27 | { 28 | private final byte baseLg; 29 | private final int num; 30 | private final Slice contents; 31 | private final int offset; 32 | private final FilterPolicy filterPolicy; 33 | 34 | FilterBlockReader(FilterPolicy filterPolicy, Slice contents) 35 | { 36 | this.filterPolicy = filterPolicy; 37 | final int n = contents.length(); 38 | final int lgAndOffset = 5; 39 | if (n < lgAndOffset) { //1 byte for baseLg and 4 for start of offset array 40 | this.baseLg = 0; 41 | this.contents = null; 42 | this.num = 0; 43 | this.offset = 0; 44 | return; 45 | } 46 | baseLg = contents.getByte(n - 1); 47 | offset = contents.getInt(n - lgAndOffset); 48 | if (offset > n - lgAndOffset) { 49 | this.num = 0; 50 | this.contents = null; 51 | return; 52 | } 53 | num = (n - lgAndOffset - offset) / 4; 54 | this.contents = contents; 55 | } 56 | 57 | public boolean keyMayMatch(long offset1, Slice key) 58 | { 59 | final int index = (int) (offset1 >> baseLg); 60 | if (index < num) { 61 | final int start = contents.getInt(this.offset + index * 4); 62 | final int limit = contents.getInt(this.offset + index * 4 + 4); 63 | if (start <= limit && limit <= offset) { 64 | Slice filter = contents.slice(start, limit - start); 65 | return filterPolicy.keyMayMatch(key, filter); 66 | } 67 | else if (start == limit) { 68 | // Empty filters do not match any keys 69 | return false; 70 | } 71 | } 72 | return true; // Errors are treated as potential matches 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/fileenv/FileLockTest.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.fileenv; 19 | 20 | import org.testng.Assert; 21 | import org.testng.annotations.Test; 22 | 23 | import java.io.File; 24 | import java.io.IOException; 25 | 26 | import static org.testng.Assert.assertFalse; 27 | import static org.testng.Assert.assertTrue; 28 | 29 | public class FileLockTest 30 | { 31 | @Test 32 | public void testNoLockAfterUnlock() throws IOException 33 | { 34 | File databaseDir = FileUtils.createTempDir("leveldb"); 35 | File lock1 = new File(databaseDir, "LOCK"); 36 | FileLock lock = FileLock.tryLock(lock1); 37 | lock.release(); 38 | assertFalse(lock1.exists()); 39 | assertTrue(databaseDir.delete()); 40 | assertFalse(databaseDir.exists()); 41 | } 42 | 43 | @Test 44 | public void testCantDoubleLock() throws IOException 45 | { 46 | File databaseDir = FileUtils.createTempDir("leveldb"); 47 | File lock1 = new File(databaseDir, "LOCK"); 48 | FileLock lock = FileLock.tryLock(lock1); 49 | try { 50 | FileLock.tryLock(new File(databaseDir, "LOCK")); 51 | Assert.fail("No expected to aquire more than once the lock"); 52 | } 53 | catch (Exception e) { 54 | //expected 55 | } 56 | lock.release(); 57 | } 58 | 59 | @Test 60 | public void testNoLockAfterLockFailure() throws IOException 61 | { 62 | File databaseDir = FileUtils.createTempDir("leveldb"); 63 | File lock1 = new File(databaseDir, "LOCK"); 64 | FileLock lock = FileLock.tryLock(lock1); 65 | try { 66 | FileLock.tryLock(new File(databaseDir, "LOCK")); 67 | Assert.fail("Can lock a already locked DB"); 68 | } 69 | catch (Exception e) { 70 | //expected 71 | } 72 | lock.release(); 73 | assertFalse(lock1.exists()); 74 | assertTrue(databaseDir.delete()); 75 | assertFalse(databaseDir.exists()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/fileenv/SequentialFileImplTest.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.fileenv; 19 | 20 | import org.iq80.leveldb.util.DynamicSliceOutput; 21 | import org.iq80.leveldb.env.SequentialFile; 22 | import org.iq80.leveldb.util.Slice; 23 | import org.testng.annotations.AfterMethod; 24 | import org.testng.annotations.BeforeMethod; 25 | import org.testng.annotations.Test; 26 | 27 | import java.io.File; 28 | import java.io.FileOutputStream; 29 | 30 | import static org.testng.AssertJUnit.assertEquals; 31 | 32 | public class SequentialFileImplTest 33 | { 34 | File file; 35 | 36 | @BeforeMethod 37 | public void setUp() throws Exception 38 | { 39 | file = File.createTempFile("test", ".log"); 40 | } 41 | 42 | @Test 43 | public void testCheckReadBounds() throws Exception 44 | { 45 | try (FileOutputStream f = new FileOutputStream(file)) { 46 | for (int i = 0; i < 200; ++i) { 47 | f.write(i); 48 | } 49 | } 50 | try (SequentialFile open = SequentialFileImpl.open(file)) { 51 | DynamicSliceOutput destination = new DynamicSliceOutput(10); 52 | assertEquals(10, open.read(10, destination)); 53 | Slice slice = destination.slice(); 54 | assertEquals(new Slice(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), slice); 55 | byte[] bytes = new byte[190]; 56 | for (int i = 10, k = 0; i < 200; ++i, k++) { 57 | bytes[k] = (byte) i; 58 | } 59 | DynamicSliceOutput destination1 = new DynamicSliceOutput(10); 60 | assertEquals(190, open.read(200, destination1)); 61 | Slice slice1 = destination1.slice(); 62 | assertEquals(new Slice(bytes), slice1); 63 | assertEquals(-1, open.read(10, new DynamicSliceOutput(10))); //EOF 64 | assertEquals(0, open.read(0, new DynamicSliceOutput(10))); //EOF 65 | } 66 | } 67 | 68 | @AfterMethod 69 | public void tearDown() 70 | { 71 | file.delete(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/Hash.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 | 19 | package org.iq80.leveldb.util; 20 | 21 | /** 22 | * @author Honore Vasconcelos 23 | */ 24 | public final class Hash 25 | { 26 | private Hash() 27 | { 28 | } 29 | 30 | public static int hash(byte[] data, int seed) 31 | { 32 | return hash(data, 0, data.length, seed); 33 | } 34 | 35 | /** 36 | * Partial array hash that start at offset and with len size. 37 | * 38 | * @param data full data 39 | * @param offset data start offset 40 | * @param len length of data 41 | * @param seed hash seed 42 | * @return hash (sign has no meaning) 43 | */ 44 | public static int hash(byte[] data, int offset, int len, int seed) 45 | { 46 | final int endIdx = len + offset; 47 | // Similar to murmur hash 48 | int m = 0xc6a4a793; 49 | int r = 24; 50 | 51 | int h = seed ^ (len * m); 52 | 53 | int idx = offset; 54 | // Pick up four bytes at a time 55 | for (; idx + 4 <= endIdx; idx += 4) { 56 | int w = byteToInt(data, idx); 57 | h += w; 58 | h *= m; 59 | h ^= (h >>> 16); 60 | } 61 | 62 | // Pick up remaining bytes 63 | final int remaining = endIdx - idx; 64 | switch (remaining) { 65 | case 3: 66 | h += (data[idx + 2] & 0xff) << 16; 67 | //FALLTHROUGH INTENDED: DO NOT PUT BREAK 68 | case 2: 69 | h += (data[idx + 1] & 0xff) << 8; 70 | //FALLTHROUGH INTENDED: DO NOT PUT BREAK 71 | case 1: 72 | h += data[idx] & 0xff; 73 | h *= m; 74 | h ^= (h >>> r); 75 | break; 76 | } 77 | return h; 78 | } 79 | 80 | private static int byteToInt(byte[] data, final int index) 81 | { 82 | return (data[index] & 0xff) | 83 | (data[index + 1] & 0xff) << 8 | 84 | (data[index + 2] & 0xff) << 16 | 85 | (data[index + 3] & 0xff) << 24; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /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 23 | implements UserComparator 24 | { 25 | @Override 26 | public String name() 27 | { 28 | return "leveldb.BytewiseComparator"; 29 | } 30 | 31 | @Override 32 | public int compare(Slice sliceA, Slice sliceB) 33 | { 34 | return sliceA.compareTo(sliceB); 35 | } 36 | 37 | @Override 38 | public Slice findShortestSeparator( 39 | Slice start, 40 | Slice limit) 41 | { 42 | // Find length of common prefix 43 | int sharedBytes = BlockBuilder.calculateSharedBytes(start, limit); 44 | 45 | // Do not shorten if one string is a prefix of the other 46 | if (sharedBytes < Math.min(start.length(), limit.length())) { 47 | // if we can add one to the last shared byte without overflow and the two keys differ by more than 48 | // one increment at this location. 49 | int lastSharedByte = start.getUnsignedByte(sharedBytes); 50 | if (lastSharedByte < 0xff && lastSharedByte + 1 < limit.getUnsignedByte(sharedBytes)) { 51 | Slice result = start.copySlice(0, sharedBytes + 1); 52 | result.setByte(sharedBytes, lastSharedByte + 1); 53 | 54 | assert (compare(result, limit) < 0) : "start must be less than last limit"; 55 | return result; 56 | } 57 | } 58 | return start; 59 | } 60 | 61 | @Override 62 | public Slice findShortSuccessor(Slice key) 63 | { 64 | // Find first character that can be incremented 65 | for (int i = 0; i < key.length(); i++) { 66 | int b = key.getUnsignedByte(i); 67 | if (b != 0xff) { 68 | Slice result = key.copySlice(0, i + 1); 69 | result.setByte(i, b + 1); 70 | return result; 71 | } 72 | } 73 | // key is a run of 0xffs. Leave it alone. 74 | return key; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/LogMessageFormatter.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.time.LocalDateTime; 21 | import java.util.function.Supplier; 22 | 23 | public final class LogMessageFormatter 24 | { 25 | private static final int DATE_SIZE = 28; 26 | private final Supplier clock; 27 | 28 | public LogMessageFormatter(Supplier clock) 29 | { 30 | this.clock = clock; 31 | } 32 | 33 | public String format(String message) 34 | { 35 | final StringBuilder sb = new StringBuilder(message.length() + DATE_SIZE); 36 | sb.append(clock.get()); 37 | sb.append(' '); 38 | sb.append(message); 39 | return sb.toString(); 40 | } 41 | 42 | public String format(String template, Object[] args) 43 | { 44 | template = String.valueOf(template); // null -> "null" 45 | 46 | // start substituting the arguments into the '%s' placeholders 47 | StringBuilder builder = new StringBuilder(DATE_SIZE + template.length() + 16 * args.length); 48 | builder.append(clock.get()); 49 | builder.append(" "); 50 | int templateStart = 0; 51 | int i = 0; 52 | while (i < args.length) { 53 | int placeholderStart = template.indexOf("%s", templateStart); 54 | if (placeholderStart == -1) { 55 | break; 56 | } 57 | builder.append(template, templateStart, placeholderStart); 58 | builder.append(args[i++]); 59 | templateStart = placeholderStart + 2; 60 | } 61 | builder.append(template, templateStart, template.length()); 62 | 63 | // if we run out of placeholders, append the extra args in square braces 64 | if (i < args.length) { 65 | builder.append(" ["); 66 | builder.append(args[i++]); 67 | while (i < args.length) { 68 | builder.append(", "); 69 | builder.append(args[i++]); 70 | } 71 | builder.append(']'); 72 | } 73 | return builder.toString(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/InternalFilterPolicy.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.google.common.base.Function; 21 | import com.google.common.collect.Lists; 22 | import org.iq80.leveldb.XFilterPolicy; 23 | import org.iq80.leveldb.util.Slice; 24 | 25 | import java.util.List; 26 | 27 | import static com.google.common.base.Preconditions.checkArgument; 28 | 29 | /** 30 | * Filter policy wrapper that converts from internal keys to user keys 31 | *

32 | *

33 | * 34 | * @author Honore Vasconcelos 35 | */ 36 | final class InternalFilterPolicy implements org.iq80.leveldb.table.FilterPolicy 37 | { 38 | private static final Function EXTRACT_USER_KEY = InternalFilterPolicy::extractUserKey; 39 | private org.iq80.leveldb.table.FilterPolicy userPolicy; 40 | 41 | private InternalFilterPolicy(org.iq80.leveldb.table.FilterPolicy userPolicy) 42 | { 43 | this.userPolicy = userPolicy; 44 | } 45 | 46 | static InternalFilterPolicy convert(XFilterPolicy policy) 47 | { 48 | checkArgument(policy == null || policy instanceof org.iq80.leveldb.table.FilterPolicy, "Filter policy must implement Java interface FilterPolicy"); 49 | if (policy instanceof InternalFilterPolicy) { 50 | return (InternalFilterPolicy) policy; 51 | } 52 | return policy == null ? null : new InternalFilterPolicy((org.iq80.leveldb.table.FilterPolicy) policy); 53 | } 54 | 55 | @Override 56 | public String name() 57 | { 58 | return userPolicy.name(); 59 | } 60 | 61 | @Override 62 | public byte[] createFilter(final List keys) 63 | { 64 | //instead of copying all the keys to a shorter form, make it lazy 65 | return userPolicy.createFilter(Lists.transform(keys, EXTRACT_USER_KEY)); 66 | } 67 | 68 | @Override 69 | public boolean keyMayMatch(Slice key, Slice filter) 70 | { 71 | return userPolicy.keyMayMatch(extractUserKey(key), filter); 72 | } 73 | 74 | private static Slice extractUserKey(Slice key) 75 | { 76 | checkArgument(key.length() >= 8); 77 | return key.slice(0, key.length() - 8); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /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 java.nio.charset.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/main/java/org/iq80/leveldb/fileenv/MmapLimiter.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.fileenv; 19 | 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | 22 | /** 23 | * Helper class to limit mmap file usage so that we do not end up 24 | * running out virtual memory or running into kernel performance 25 | * problems for very large databases. 26 | */ 27 | public final class MmapLimiter 28 | { 29 | public static final int CPU_DATA_MODEL; 30 | 31 | static { 32 | boolean is64bit; 33 | if (System.getProperty("os.name").contains("Windows")) { 34 | is64bit = System.getenv("ProgramFiles(x86)") != null; 35 | } 36 | else { 37 | is64bit = System.getProperty("os.arch").contains("64"); 38 | } 39 | CPU_DATA_MODEL = is64bit ? 64 : 32; 40 | } 41 | 42 | /** 43 | * We only use MMAP on 64 bit systems since it's really easy to run out of 44 | * virtual address space on a 32 bit system when all the data is getting mapped 45 | * into memory. If you really want to use MMAP anyways, use -Dleveldb.mmap=true 46 | */ 47 | public static final boolean USE_MMAP = Boolean.parseBoolean(System.getProperty("leveldb.mmap", String.valueOf(CPU_DATA_MODEL > 32))); 48 | 49 | private AtomicInteger maxAllowedMmap; 50 | 51 | private MmapLimiter(int maxAllowedMmap) 52 | { 53 | this.maxAllowedMmap = new AtomicInteger(maxAllowedMmap); 54 | } 55 | 56 | /** 57 | * Up to 1000 mmaps for 64-bit JVM; none for 32bit. 58 | */ 59 | public static MmapLimiter defaultLimiter() 60 | { 61 | return new MmapLimiter(USE_MMAP ? 1000 : 0); 62 | } 63 | 64 | public static MmapLimiter newLimiter(int maxAllowedMmap) 65 | { 66 | return new MmapLimiter(maxAllowedMmap); 67 | } 68 | 69 | /** 70 | * If another mmap slot is available, acquire it and return true. 71 | * Else return false. 72 | */ 73 | public boolean acquire() 74 | { 75 | return maxAllowedMmap.getAndDecrement() > 0; 76 | } 77 | 78 | /** 79 | * Release a slot acquired by a previous call to Acquire() that returned true. 80 | */ 81 | public void release() 82 | { 83 | maxAllowedMmap.incrementAndGet(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/iterator/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.iterator; 19 | 20 | import org.iq80.leveldb.impl.InternalKey; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import java.io.IOException; 24 | 25 | public class InternalTableIterator 26 | implements InternalIterator 27 | { 28 | private final SliceIterator tableIterator; 29 | private InternalKey key; 30 | 31 | public InternalTableIterator(SliceIterator tableIterator) 32 | { 33 | this.tableIterator = tableIterator; 34 | } 35 | 36 | @Override 37 | public boolean valid() 38 | { 39 | return tableIterator.valid(); 40 | } 41 | 42 | @Override 43 | public boolean seekToFirst() 44 | { 45 | this.key = null; 46 | return tableIterator.seekToFirst(); 47 | } 48 | 49 | public boolean seek(InternalKey targetKey) 50 | { 51 | this.key = null; 52 | return tableIterator.seek(targetKey.encode()); 53 | } 54 | 55 | @Override 56 | public boolean seekToLast() 57 | { 58 | this.key = null; 59 | return tableIterator.seekToLast(); 60 | } 61 | 62 | @Override 63 | public boolean next() 64 | { 65 | this.key = null; 66 | return tableIterator.next(); 67 | } 68 | 69 | @Override 70 | public boolean prev() 71 | { 72 | this.key = null; 73 | return tableIterator.prev(); 74 | } 75 | 76 | @Override 77 | public InternalKey key() 78 | { 79 | if (key == null) { 80 | //cache key decomposition 81 | this.key = new InternalKey(tableIterator.key()); 82 | } 83 | return this.key; 84 | } 85 | 86 | @Override 87 | public Slice value() 88 | { 89 | return tableIterator.value(); 90 | } 91 | 92 | @Override 93 | public String toString() 94 | { 95 | return "InternalTableIterator" + 96 | "{fromIterator=" + tableIterator + 97 | '}'; 98 | } 99 | 100 | @Override 101 | public void close() throws IOException 102 | { 103 | this.key = null; 104 | tableIterator.close(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/fileenv/MMRandomInputFile.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.fileenv; 19 | 20 | import com.google.common.io.Files; 21 | import org.iq80.leveldb.env.RandomInputFile; 22 | 23 | import java.io.File; 24 | import java.io.IOException; 25 | import java.nio.ByteBuffer; 26 | import java.nio.ByteOrder; 27 | import java.nio.MappedByteBuffer; 28 | 29 | import static java.util.Objects.requireNonNull; 30 | 31 | /** 32 | * Memory mapped filed table. 33 | * 34 | * @author Honore Vasconcelos 35 | */ 36 | class MMRandomInputFile implements RandomInputFile 37 | { 38 | private final String file; 39 | private final long size; 40 | private final MappedByteBuffer data; 41 | 42 | private MMRandomInputFile(String file, MappedByteBuffer data, long size) 43 | { 44 | this.file = file; 45 | this.size = size; 46 | this.data = data; 47 | } 48 | 49 | /** 50 | * Open file using memory mapped file access. 51 | * @param file file to open 52 | * @return readable file 53 | * @throws IOException If some other I/O error occurs 54 | */ 55 | public static RandomInputFile open(File file) throws IOException 56 | { 57 | requireNonNull(file, "file is null"); 58 | MappedByteBuffer map = Files.map(file); 59 | 60 | return new MMRandomInputFile(file.getAbsolutePath(), map, map.capacity()); 61 | } 62 | 63 | @Override 64 | public long size() 65 | { 66 | return size; 67 | } 68 | 69 | @Override 70 | public ByteBuffer read(long offset, int length) 71 | { 72 | int newPosition = (int) (data.position() + offset); 73 | return (ByteBuffer) data.duplicate().order(ByteOrder.LITTLE_ENDIAN).clear().limit(newPosition + length).position(newPosition); 74 | } 75 | 76 | @Override 77 | public void close() throws IOException 78 | { 79 | try { 80 | ByteBufferSupport.unmap(data); 81 | } 82 | catch (Exception e) { 83 | throw new IOException("Unable to unmap file", e); 84 | } 85 | } 86 | 87 | @Override 88 | public String toString() 89 | { 90 | return "MMTableDataSource{" + 91 | "file='" + file + '\'' + 92 | ", size=" + size + 93 | '}'; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /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 org.iq80.leveldb.util.Slice; 21 | 22 | import java.util.Map.Entry; 23 | 24 | import static java.nio.charset.StandardCharsets.UTF_8; 25 | import static java.util.Objects.requireNonNull; 26 | 27 | public class InternalEntry 28 | implements Entry 29 | { 30 | private final InternalKey key; 31 | private final Slice value; 32 | 33 | public InternalEntry(InternalKey key, Slice value) 34 | { 35 | requireNonNull(key, "key is null"); 36 | requireNonNull(value, "value is null"); 37 | this.key = key; 38 | this.value = value; 39 | } 40 | 41 | @Override 42 | public InternalKey getKey() 43 | { 44 | return key; 45 | } 46 | 47 | @Override 48 | public Slice getValue() 49 | { 50 | return value; 51 | } 52 | 53 | /** 54 | * @throws UnsupportedOperationException always 55 | */ 56 | @Override 57 | public final Slice setValue(Slice value) 58 | { 59 | throw new UnsupportedOperationException(); 60 | } 61 | 62 | @Override 63 | public boolean equals(Object o) 64 | { 65 | if (this == o) { 66 | return true; 67 | } 68 | if (o == null || getClass() != o.getClass()) { 69 | return false; 70 | } 71 | 72 | InternalEntry entry = (InternalEntry) o; 73 | 74 | if (!key.equals(entry.key)) { 75 | return false; 76 | } 77 | if (!value.equals(entry.value)) { 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | @Override 85 | public int hashCode() 86 | { 87 | int result = key.hashCode(); 88 | result = 31 * result + value.hashCode(); 89 | return result; 90 | } 91 | 92 | @Override 93 | public String toString() 94 | { 95 | StringBuilder sb = new StringBuilder(); 96 | sb.append("InternalEntry"); 97 | sb.append("{key=").append(key); // todo don't print the real value 98 | sb.append(", value=").append(value.toString(UTF_8)); 99 | sb.append('}'); 100 | return sb.toString(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /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 | { 24 | private final long number; 25 | 26 | /** 27 | * File size in bytes 28 | */ 29 | private final long fileSize; 30 | 31 | /** 32 | * Smallest internal key served by table 33 | */ 34 | private final InternalKey smallest; 35 | 36 | /** 37 | * Largest internal key served by table 38 | */ 39 | private final InternalKey largest; 40 | 41 | /** 42 | * Seeks allowed until compaction 43 | */ 44 | // todo this mutable state should be moved elsewhere 45 | private final AtomicInteger allowedSeeks = new AtomicInteger(1 << 30); 46 | 47 | public FileMetaData(long number, long fileSize, InternalKey smallest, InternalKey largest) 48 | { 49 | this.number = number; 50 | this.fileSize = fileSize; 51 | this.smallest = smallest.compact(); 52 | this.largest = largest.compact(); 53 | } 54 | 55 | public long getFileSize() 56 | { 57 | return fileSize; 58 | } 59 | 60 | public long getNumber() 61 | { 62 | return number; 63 | } 64 | 65 | public InternalKey getSmallest() 66 | { 67 | return smallest; 68 | } 69 | 70 | public InternalKey getLargest() 71 | { 72 | return largest; 73 | } 74 | 75 | public int getAllowedSeeks() 76 | { 77 | return allowedSeeks.get(); 78 | } 79 | 80 | public void setAllowedSeeks(int allowedSeeks) 81 | { 82 | this.allowedSeeks.set(allowedSeeks); 83 | } 84 | 85 | public void decrementAllowedSeeks() 86 | { 87 | allowedSeeks.getAndDecrement(); 88 | } 89 | 90 | @Override 91 | public String toString() 92 | { 93 | StringBuilder sb = new StringBuilder(); 94 | sb.append("FileMetaData"); 95 | sb.append("{number=").append(number); 96 | sb.append(", fileSize=").append(fileSize); 97 | sb.append(", smallest=").append(smallest); 98 | sb.append(", largest=").append(largest); 99 | sb.append(", allowedSeeks=").append(allowedSeeks); 100 | sb.append('}'); 101 | return sb.toString(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /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 org.iq80.leveldb.iterator.MemTableIterator; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import java.util.Map.Entry; 24 | import java.util.concurrent.ConcurrentSkipListMap; 25 | import java.util.concurrent.atomic.AtomicLong; 26 | 27 | import static java.util.Objects.requireNonNull; 28 | import static org.iq80.leveldb.util.SizeOf.SIZE_OF_LONG; 29 | 30 | public class MemTable 31 | { 32 | private final ConcurrentSkipListMap table; 33 | private final AtomicLong approximateMemoryUsage = new AtomicLong(); 34 | 35 | public MemTable(InternalKeyComparator internalKeyComparator) 36 | { 37 | table = new ConcurrentSkipListMap<>(internalKeyComparator); 38 | } 39 | 40 | public boolean isEmpty() 41 | { 42 | return table.isEmpty(); 43 | } 44 | 45 | public long approximateMemoryUsage() 46 | { 47 | return approximateMemoryUsage.get(); 48 | } 49 | 50 | public void add(long sequenceNumber, ValueType valueType, Slice key, Slice value) 51 | { 52 | requireNonNull(valueType, "valueType is null"); 53 | requireNonNull(key, "key is null"); 54 | requireNonNull(valueType, "valueType is null"); 55 | 56 | InternalKey internalKey = new InternalKey(key, sequenceNumber, valueType); 57 | table.put(internalKey, value); 58 | 59 | approximateMemoryUsage.addAndGet(key.length() + SIZE_OF_LONG + value.length()); 60 | } 61 | 62 | public LookupResult get(LookupKey key) 63 | { 64 | requireNonNull(key, "key is null"); 65 | 66 | InternalKey internalKey = key.getInternalKey(); 67 | Entry entry = table.ceilingEntry(internalKey); 68 | if (entry == null) { 69 | return null; 70 | } 71 | 72 | InternalKey entryKey = entry.getKey(); 73 | if (entryKey.getUserKey().equals(key.getUserKey())) { 74 | if (entryKey.getValueType() == ValueType.DELETION) { 75 | return LookupResult.deleted(key); 76 | } 77 | else { 78 | return LookupResult.ok(key, entry.getValue()); 79 | } 80 | } 81 | return null; 82 | } 83 | 84 | public MemTableIterator iterator() 85 | { 86 | return new MemTableIterator(table); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/util/TestUtils.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.ByteArrayOutputStream; 21 | import java.io.IOException; 22 | import java.util.Arrays; 23 | import java.util.Random; 24 | 25 | import static java.nio.charset.StandardCharsets.US_ASCII; 26 | 27 | public final class TestUtils 28 | { 29 | private TestUtils() 30 | { 31 | //utility 32 | } 33 | 34 | public static Slice randomString(Random rnd, int len) 35 | { 36 | final byte[] bytes = new byte[len]; 37 | for (int i = 0; i < len; i++) { 38 | bytes[i] = (byte) (' ' + rnd.nextInt(95)); // ' ' .. '~' 39 | } 40 | return new Slice(bytes); 41 | } 42 | 43 | public static byte[] randomKey(Random rnd, int len) 44 | { 45 | // Make sure to generate a wide variety of characters so we 46 | // test the boundary conditions for short-key optimizations. 47 | byte[] kTestChars = { 48 | 0, 1, 'a', 'b', 'c', 'd', 'e', (byte) 0xfd, (byte) 0xfe, (byte) 0xff 49 | }; 50 | byte[] result = new byte[len]; 51 | for (int i = 0; i < len; i++) { 52 | result[i] = kTestChars[rnd.nextInt(kTestChars.length)]; 53 | } 54 | return result; 55 | } 56 | 57 | public static Slice compressibleString(Random rnd, double compressedFraction, int len) throws IOException 58 | { 59 | int raw = (int) (len * compressedFraction); 60 | if (raw < 1) { 61 | raw = 1; 62 | } 63 | final byte[] bytes = randomString(rnd, raw).getBytes(); 64 | 65 | final ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(len); 66 | while (byteOutputStream.size() < len) { 67 | byteOutputStream.write(bytes); 68 | } 69 | final Slice slice = new Slice(byteOutputStream.toByteArray()); 70 | byteOutputStream.close(); 71 | return slice; 72 | } 73 | 74 | public static String longString(int length, char character) 75 | { 76 | char[] chars = new char[length]; 77 | Arrays.fill(chars, character); 78 | return new String(chars); 79 | } 80 | 81 | public static Slice asciiToSlice(String value) 82 | { 83 | return Slices.copiedBuffer(value, US_ASCII); 84 | } 85 | 86 | public static byte[] asciiToBytes(String value) 87 | { 88 | return asciiToSlice(value).getBytes(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/util/SafeListBuilderTest.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.Assert; 21 | import org.testng.annotations.Test; 22 | 23 | import java.io.Closeable; 24 | import java.io.IOException; 25 | import java.util.List; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | 28 | import static org.testng.Assert.assertEquals; 29 | import static org.testng.Assert.assertTrue; 30 | 31 | public class SafeListBuilderTest 32 | { 33 | @Test 34 | public void testAllElementAreClosedEvenOnError() throws Exception 35 | { 36 | AtomicInteger counter = new AtomicInteger(); 37 | SafeListBuilder builder = SafeListBuilder.builder(); 38 | builder.add(counter::incrementAndGet); 39 | builder.add(() -> { 40 | counter.incrementAndGet(); 41 | throw new IOException(); 42 | }); 43 | builder.add(counter::incrementAndGet); 44 | builder.add(() -> { 45 | counter.incrementAndGet(); 46 | throw new IOException(); 47 | }); 48 | builder.add(counter::incrementAndGet); 49 | assertEquals(counter.get(), 0); 50 | try { 51 | builder.close(); 52 | Assert.fail("should fail because not all close succeed"); 53 | } 54 | catch (Exception e) { 55 | assertTrue(e instanceof IOException); 56 | } 57 | assertEquals(counter.get(), 5); 58 | } 59 | 60 | @Test 61 | public void testCloseWithoutExceptions() throws Exception 62 | { 63 | AtomicInteger counter = new AtomicInteger(); 64 | SafeListBuilder builder = SafeListBuilder.builder(); 65 | builder.add(counter::incrementAndGet); 66 | builder.add(counter::incrementAndGet); 67 | builder.close(); 68 | assertEquals(counter.get(), 2); 69 | } 70 | 71 | @Test 72 | public void testNothingHappenIfBuildWasCalled() throws Exception 73 | { 74 | AtomicInteger counter = new AtomicInteger(); 75 | try (SafeListBuilder builder = SafeListBuilder.builder()) { 76 | builder.add(counter::incrementAndGet); 77 | builder.add(counter::incrementAndGet); 78 | builder.add(counter::incrementAndGet); 79 | final List build = builder.build(); 80 | assertEquals(3, build.size()); 81 | } 82 | assertEquals(counter.get(), 0); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /leveldb-benchmark/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 4.0.0 20 | 21 | 22 | com.hivemc.leveldb 23 | leveldb-project 24 | 1.1.0 25 | 26 | 27 | leveldb-benchmark 28 | leveldb-benchmark 29 | Port of LevelDB Benchmarks to Java 30 | 31 | 32 | ${project.parent.basedir} 33 | false 34 | 35 | 36 | 37 | 38 | com.hivemc.leveldb 39 | leveldb-api 40 | 41 | 42 | com.hivemc.leveldb 43 | leveldb 44 | 45 | 46 | com.google.guava 47 | guava 48 | 49 | 50 | junit 51 | junit 52 | 4.13.1 53 | test 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.codehaus.mojo 62 | exec-maven-plugin 63 | 1.2.1 64 | 65 | 66 | 67 | java 68 | 69 | 70 | 71 | 72 | org.iq80.leveldb.benchmark.DbBenchmark 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /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 com.google.common.base.Throwables; 21 | 22 | import java.io.Closeable; 23 | import java.io.IOException; 24 | import java.util.concurrent.Callable; 25 | 26 | public final class Closeables 27 | { 28 | private Closeables() 29 | { 30 | } 31 | 32 | public static void closeQuietly(Closeable closeable) 33 | { 34 | if (closeable == null) { 35 | return; 36 | } 37 | try { 38 | closeable.close(); 39 | } 40 | catch (IOException ignored) { 41 | } 42 | } 43 | 44 | public static void closeAll(Iterable closeables) throws IOException 45 | { 46 | Throwable throwable = null; 47 | for (Closeable closeable : closeables) { 48 | try { 49 | closeable.close(); 50 | } 51 | catch (Throwable e) { 52 | if (throwable == null) { 53 | throwable = e; 54 | } 55 | else { 56 | throwable.addSuppressed(e); 57 | } 58 | } 59 | } 60 | 61 | if (throwable != null) { 62 | Throwables.propagateIfPossible(throwable, IOException.class); 63 | throw new AssertionError(throwable); // not possible 64 | } 65 | } 66 | 67 | /** 68 | * Create a wrapper for {@code resource}. If wrapper fail to be created, resource is properly closed. 69 | * In the case if {@code wrapperFactory.call()} succeed, returned object is responsible to close {@code resource}. 70 | * 71 | * @param wrapperFactory wrapper factory 72 | * @param resource resource used by wrapper 73 | * @param wrapper object type 74 | * @return resource wrapper instance 75 | * @throws IOException in the case of any exception. 76 | */ 77 | public static T wrapResource(Callable wrapperFactory, Closeable resource) throws IOException 78 | { 79 | try { 80 | return wrapperFactory.call(); 81 | } 82 | catch (Throwable throwable) { 83 | try { 84 | resource.close(); 85 | } 86 | catch (Throwable e1) { 87 | throwable.addSuppressed(e1); 88 | } 89 | Throwables.propagateIfPossible(throwable, IOException.class); 90 | throw new AssertionError(throwable); // not possible 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/iterator/SeekingIterators.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.iterator; 19 | 20 | import org.iq80.leveldb.impl.InternalKey; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import java.io.Closeable; 24 | import java.util.Comparator; 25 | import java.util.List; 26 | import java.util.function.Function; 27 | 28 | /** 29 | * When ever possible a specific interface implementation is created for speed purpose. 30 | * see {@link DbIterator} where the same approach is used. 31 | */ 32 | public final class SeekingIterators 33 | { 34 | private SeekingIterators() 35 | { 36 | //utility 37 | } 38 | 39 | /** 40 | * Seeking iterator based on provided sorted list. Unpredictable behavior 41 | * will happen if {@code list} is not sorted according to {@code comparator} 42 | */ 43 | public static SeekingIterator fromSortedList(List list, Function keyExtractor, Function valueExtractor, Comparator comparator) 44 | { 45 | return new SortedCollectionIterator<>(list, keyExtractor, valueExtractor, comparator); 46 | } 47 | 48 | public static SliceIterator twoLevelSliceIterator(SliceIterator indexIterator, Function> blockFunction, Closeable closeableResources) 49 | { 50 | return new SliceTwoLevelIterator(indexIterator, blockFunction, closeableResources); 51 | } 52 | 53 | public static InternalIterator twoLevelInternalIterator(SeekingIterator indexIterator, Function> blockFunction, Closeable closeableResources) 54 | { 55 | return new InternalTwoLevelIterator<>(indexIterator, blockFunction, closeableResources); 56 | } 57 | 58 | private static class InternalTwoLevelIterator extends TwoLevelIterator implements InternalIterator 59 | { 60 | InternalTwoLevelIterator(SeekingIterator indexIterator, Function> blockFunction, Closeable closeableResources) 61 | { 62 | super(indexIterator, blockFunction, closeableResources); 63 | } 64 | } 65 | 66 | private static class SliceTwoLevelIterator extends TwoLevelIterator implements SliceIterator 67 | { 68 | SliceTwoLevelIterator(SliceIterator indexIterator, Function> blockFunction, Closeable closeableResources) 69 | { 70 | super(indexIterator, blockFunction, closeableResources); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/fileenv/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.fileenv; 19 | 20 | import com.google.common.base.Throwables; 21 | 22 | import java.lang.invoke.MethodHandle; 23 | import java.lang.invoke.MethodHandles; 24 | import java.lang.invoke.MethodType; 25 | import java.lang.reflect.Field; 26 | import java.lang.reflect.Method; 27 | import java.nio.ByteBuffer; 28 | import java.nio.MappedByteBuffer; 29 | 30 | final class ByteBufferSupport 31 | { 32 | private static final MethodHandle INVOKE_CLEANER; 33 | 34 | static { 35 | MethodHandle invoker; 36 | try { 37 | // Java 9 added an invokeCleaner method to Unsafe to work around 38 | // module visibility issues for code that used to rely on DirectByteBuffer's cleaner() 39 | Class unsafeClass = Class.forName("sun.misc.Unsafe"); 40 | Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); 41 | theUnsafe.setAccessible(true); 42 | invoker = MethodHandles.lookup() 43 | .findVirtual(unsafeClass, "invokeCleaner", MethodType.methodType(void.class, ByteBuffer.class)) 44 | .bindTo(theUnsafe.get(null)); 45 | } 46 | catch (Exception e) { 47 | // fall back to pre-java 9 compatible behavior 48 | try { 49 | Class directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); 50 | Class cleanerClass = Class.forName("sun.misc.Cleaner"); 51 | 52 | Method cleanerMethod = directByteBufferClass.getDeclaredMethod("cleaner"); 53 | cleanerMethod.setAccessible(true); 54 | MethodHandle getCleaner = MethodHandles.lookup().unreflect(cleanerMethod); 55 | 56 | Method cleanMethod = cleanerClass.getDeclaredMethod("clean"); 57 | cleanerMethod.setAccessible(true); 58 | MethodHandle clean = MethodHandles.lookup().unreflect(cleanMethod); 59 | 60 | clean = MethodHandles.dropArguments(clean, 1, directByteBufferClass); 61 | invoker = MethodHandles.foldArguments(clean, getCleaner); 62 | } 63 | catch (Exception e1) { 64 | throw new AssertionError(e1); 65 | } 66 | } 67 | INVOKE_CLEANER = invoker; 68 | } 69 | 70 | private ByteBufferSupport() 71 | { 72 | } 73 | 74 | public static void unmap(MappedByteBuffer buffer) 75 | { 76 | try { 77 | INVOKE_CLEANER.invoke(buffer); 78 | } 79 | catch (Throwable ignored) { 80 | throw Throwables.propagate(ignored); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/impl/Iq80DBFactory.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.DB; 21 | import org.iq80.leveldb.DBFactory; 22 | import org.iq80.leveldb.Options; 23 | import org.iq80.leveldb.env.Env; 24 | import org.iq80.leveldb.fileenv.EnvImpl; 25 | 26 | import java.io.BufferedReader; 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.io.InputStreamReader; 31 | 32 | import static java.nio.charset.StandardCharsets.UTF_8; 33 | import static java.util.Objects.requireNonNull; 34 | 35 | /** 36 | * @author Hiram Chirino 37 | */ 38 | public class Iq80DBFactory 39 | implements DBFactory 40 | { 41 | public static final String VERSION; 42 | 43 | static { 44 | String v = "unknown"; 45 | InputStream is = Iq80DBFactory.class.getResourceAsStream("version.txt"); 46 | try { 47 | v = new BufferedReader(new InputStreamReader(is, UTF_8)).readLine(); 48 | } 49 | catch (Throwable e) { 50 | } 51 | finally { 52 | try { 53 | is.close(); 54 | } 55 | catch (Throwable e) { 56 | } 57 | } 58 | VERSION = v; 59 | } 60 | 61 | public static final Iq80DBFactory factory = new Iq80DBFactory(); 62 | 63 | @Override 64 | public DB open(File path, Options options) 65 | throws IOException 66 | { 67 | requireNonNull(path, "path is null"); 68 | return new DbImpl(options, path.getAbsolutePath(), EnvImpl.createEnv()); 69 | } 70 | 71 | @Override 72 | public void destroy(File path, Options options) 73 | throws IOException 74 | { 75 | requireNonNull(path, "path is null"); 76 | Env env = EnvImpl.createEnv(); 77 | DbImpl.destroyDB(env.toFile(path.getAbsolutePath()), env); 78 | } 79 | 80 | @Override 81 | public void repair(File path, Options options) 82 | throws IOException 83 | { 84 | // TODO: implement repair 85 | throw new UnsupportedOperationException(); 86 | } 87 | 88 | @Override 89 | public String toString() 90 | { 91 | return String.format("iq80 leveldb version %s", VERSION); 92 | } 93 | 94 | public static byte[] bytes(String value) 95 | { 96 | return (value == null) ? null : value.getBytes(UTF_8); 97 | } 98 | 99 | public static String asString(byte[] value) 100 | { 101 | return (value == null) ? null : new String(value, UTF_8); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/iterator/SeekingDBIteratorAdapter.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.iterator; 19 | 20 | import org.iq80.leveldb.DBIterator; 21 | 22 | import java.util.Map; 23 | import java.util.function.Function; 24 | 25 | public class SeekingDBIteratorAdapter extends ASeekingIterator 26 | { 27 | private final DBIterator iterator; 28 | private final Function toKey; 29 | private final Function key; 30 | private final Function value; 31 | private Map.Entry entry; 32 | 33 | private SeekingDBIteratorAdapter(DBIterator iterator, Function toKey, Function key, Function value) 34 | { 35 | this.iterator = iterator; 36 | this.toKey = toKey; 37 | this.key = key; 38 | this.value = value; 39 | } 40 | 41 | public static SeekingIterator toSeekingIterator(DBIterator iterator, Function toKey, Function key, Function value) 42 | { 43 | return new SeekingDBIteratorAdapter<>(iterator, toKey, key, value); 44 | } 45 | 46 | @Override 47 | protected boolean internalSeekToFirst() 48 | { 49 | iterator.seekToFirst(); 50 | entry = iterator.hasNext() ? iterator.next() : null; 51 | return entry != null; 52 | } 53 | 54 | @Override 55 | protected boolean internalSeekToLast() 56 | { 57 | iterator.seekToLast(); 58 | entry = iterator.hasPrev() ? iterator.prev() : null; 59 | return entry != null; 60 | } 61 | 62 | @Override 63 | protected boolean internalSeek(K key) 64 | { 65 | iterator.seek(this.toKey.apply(key)); 66 | entry = iterator.hasNext() ? iterator.next() : null; 67 | return entry != null; 68 | } 69 | 70 | @Override 71 | protected boolean internalNext(boolean switchDirection) 72 | { 73 | entry = iterator.hasNext() ? iterator.next() : null; 74 | return entry != null; 75 | } 76 | 77 | @Override 78 | protected boolean internalPrev(boolean switchDirection) 79 | { 80 | entry = iterator.hasPrev() ? iterator.prev() : null; 81 | return entry != null; 82 | } 83 | 84 | @Override 85 | protected K internalKey() 86 | { 87 | return key.apply(entry.getKey()); 88 | } 89 | 90 | @Override 91 | protected V internalValue() 92 | { 93 | return value.apply(entry.getValue()); 94 | } 95 | 96 | @Override 97 | protected void internalClose() 98 | { 99 | entry = null; 100 | iterator.close(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/util/ZLib.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.IOException; 21 | import java.nio.ByteBuffer; 22 | import java.util.zip.DataFormatException; 23 | import java.util.zip.Deflater; 24 | import java.util.zip.Inflater; 25 | 26 | /** 27 | * A wrapper for java based ZLib 28 | */ 29 | public final class ZLib 30 | { 31 | private static final ThreadLocal INFLATER = ThreadLocal.withInitial(Inflater::new); 32 | private static final ThreadLocal INFLATER_RAW = ThreadLocal.withInitial(() -> new Inflater(true)); 33 | private static final ThreadLocal DEFLATER = ThreadLocal.withInitial(Deflater::new); 34 | private static final ThreadLocal DEFLATER_RAW = ThreadLocal.withInitial(() -> new Deflater(Deflater.DEFAULT_COMPRESSION, true)); 35 | 36 | private ZLib() 37 | { 38 | } 39 | 40 | public static ByteBuffer uncompress(ByteBuffer compressed, boolean raw) throws IOException 41 | { 42 | Inflater inflater = (raw ? INFLATER_RAW : INFLATER).get(); 43 | try { 44 | ByteBuffer buffer = ByteBuffer.allocate(Math.max(1024, compressed.remaining() * 2)); 45 | inflater.setInput(compressed); 46 | while (!inflater.finished()) { 47 | if (inflater.inflate(buffer) == 0) { 48 | // Grow buffer 49 | ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() + Math.max(1024, (compressed.remaining() * 2))); 50 | int position = buffer.position(); 51 | 52 | // Reset reader index 53 | buffer.flip(); 54 | newBuffer.put(buffer); 55 | 56 | // Set position to the original 57 | newBuffer.position(position); 58 | buffer = newBuffer; 59 | } 60 | } 61 | 62 | // Flip buffer 63 | buffer.flip(); 64 | return buffer; 65 | } 66 | catch (DataFormatException e) { 67 | throw new IOException(e); 68 | } 69 | finally { 70 | inflater.reset(); 71 | } 72 | } 73 | 74 | public static int compress(byte[] input, int inputOffset, int length, byte[] output, int outputOffset, boolean raw) 75 | throws IOException 76 | { 77 | Deflater deflater = (raw ? DEFLATER_RAW : DEFLATER).get(); 78 | try { 79 | deflater.setInput(input, inputOffset, length); 80 | deflater.finish(); 81 | 82 | return deflater.deflate(output, outputOffset, output.length - outputOffset); 83 | } 84 | finally { 85 | deflater.reset(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /leveldb-api/src/test/java/org/iq80/leveldb/OptionsTest.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 org.testng.annotations.Test; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | public class OptionsTest 25 | { 26 | @Test(expectedExceptions = IllegalArgumentException.class) 27 | public void testDefaults() throws Exception 28 | { 29 | Options.fromOptions(null); 30 | } 31 | 32 | @Test 33 | public void testCopy() throws Exception 34 | { 35 | MyDBComparator comparator = new MyDBComparator(); 36 | Logger logger = msg -> { 37 | }; 38 | XFilterPolicy filterPolicy = new XFilterPolicy() 39 | { 40 | }; 41 | Options op = new Options(); 42 | op.createIfMissing(false); 43 | op.errorIfExists(true); 44 | op.writeBufferSize(1234); 45 | op.maxFileSize(56790); 46 | op.maxOpenFiles(2); 47 | op.blockRestartInterval(789); 48 | op.blockSize(345); 49 | op.compressionType(CompressionType.NONE); 50 | op.paranoidChecks(true); 51 | op.comparator(comparator); 52 | op.logger(logger); 53 | op.cacheSize(678); 54 | op.filterPolicy(filterPolicy); 55 | op.reuseLogs(true); 56 | Options op2 = Options.fromOptions(op); 57 | 58 | assertEquals(op2.createIfMissing(), false); 59 | assertEquals(op2.errorIfExists(), true); 60 | assertEquals(op2.writeBufferSize(), 1234); 61 | assertEquals(op2.maxFileSize(), 56790); 62 | assertEquals(op2.maxOpenFiles(), 2); 63 | assertEquals(op2.blockRestartInterval(), 789); 64 | assertEquals(op2.blockSize(), 345); 65 | assertEquals(op2.compressionType(), CompressionType.NONE); 66 | assertEquals(op2.paranoidChecks(), true); 67 | assertEquals(op2.comparator(), comparator); 68 | assertEquals(op2.logger(), logger); 69 | assertEquals(op2.cacheSize(), 678); 70 | assertEquals(op2.filterPolicy(), filterPolicy); 71 | assertEquals(op2.reuseLogs(), true); 72 | } 73 | 74 | private static class MyDBComparator implements DBComparator 75 | { 76 | @Override 77 | public String name() 78 | { 79 | return null; 80 | } 81 | 82 | @Override 83 | public byte[] findShortestSeparator(byte[] start, byte[] limit) 84 | { 85 | return new byte[0]; 86 | } 87 | 88 | @Override 89 | public byte[] findShortSuccessor(byte[] key) 90 | { 91 | return new byte[0]; 92 | } 93 | 94 | @Override 95 | public int compare(byte[] o1, byte[] o2) 96 | { 97 | return 0; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/fileenv/FileLock.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.fileenv; 19 | 20 | import org.iq80.leveldb.DBException; 21 | import org.iq80.leveldb.env.DbLock; 22 | import org.iq80.leveldb.util.Closeables; 23 | 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.io.RandomAccessFile; 27 | import java.nio.channels.FileChannel; 28 | 29 | import static java.lang.String.format; 30 | import static java.util.Objects.requireNonNull; 31 | 32 | class FileLock implements DbLock 33 | { 34 | private final File lockFile; 35 | private final FileChannel channel; 36 | private final java.nio.channels.FileLock lock; 37 | 38 | private FileLock(File lockFile, FileChannel channel, java.nio.channels.FileLock lock) 39 | { 40 | this.lockFile = lockFile; 41 | this.channel = channel; 42 | this.lock = lock; 43 | } 44 | 45 | /** 46 | * Attempts to acquire an exclusive lock on this file 47 | * 48 | * @param lockFile lock file 49 | * @return releasable db lock 50 | * @throws IOException If lock is already held or some other I/O error occurs 51 | */ 52 | public static FileLock tryLock(File lockFile) throws IOException 53 | { 54 | requireNonNull(lockFile, "lockFile is null"); 55 | // open and lock the file 56 | final FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel(); 57 | try { 58 | java.nio.channels.FileLock lock = channel.tryLock(); 59 | if (lock == null) { 60 | throw new IOException(format("Unable to acquire lock on '%s'", lockFile.getAbsolutePath())); 61 | } 62 | return new FileLock(lockFile, channel, lock); 63 | } 64 | catch (Exception e) { 65 | Closeables.closeQuietly(channel); 66 | throw new IOException(format("Unable to acquire lock on '%s'", lockFile.getAbsolutePath()), e); 67 | } 68 | } 69 | 70 | @Override 71 | public boolean isValid() 72 | { 73 | return lock.isValid(); 74 | } 75 | 76 | @Override 77 | public void release() 78 | { 79 | try (FileChannel closeMe = channel) { 80 | lock.release(); 81 | } 82 | catch (IOException e) { 83 | throw new DBException(e); 84 | } 85 | finally { 86 | lockFile.delete(); 87 | } 88 | } 89 | 90 | @Override 91 | public String toString() 92 | { 93 | StringBuilder sb = new StringBuilder(); 94 | sb.append("DbLock"); 95 | sb.append("{lockFile=").append(lockFile); 96 | sb.append(", lock=").append(lock); 97 | sb.append('}'); 98 | return sb.toString(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /leveldb/src/main/java/org/iq80/leveldb/iterator/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.iterator; 19 | 20 | import org.iq80.leveldb.impl.InternalKey; 21 | import org.iq80.leveldb.util.Slice; 22 | 23 | import java.io.IOException; 24 | 25 | public final class DbIterator implements InternalIterator 26 | { 27 | /* 28 | * NOTE: This code has been specifically tuned for performance of the DB 29 | * iterator methods. Before committing changes to this code, make sure 30 | * that the performance of the DB benchmark with the following parameters 31 | * has not regressed: 32 | * 33 | * --num=10000000 --benchmarks=fillseq,readrandom,readseq,readseq,readseq 34 | * 35 | * The code in this class purposely does not use the SeekingIterator 36 | * interface, but instead used the concrete implementations. This is 37 | * because we want the hot spot compiler to inline the code from the 38 | * concrete iterators, and this can not happen with truly polymorphic 39 | * call-sites. If a future version of hot spot supports inlining of truly 40 | * polymorphic call-sites, this code can be made much simpler. 41 | */ 42 | private final MergingIterator mergingIterator; 43 | private final Runnable cleanup; 44 | 45 | public DbIterator(MergingIterator mergingIterator, Runnable cleanup) 46 | { 47 | this.mergingIterator = mergingIterator; 48 | this.cleanup = cleanup; 49 | } 50 | 51 | @Override 52 | public void close() throws IOException 53 | { 54 | //end user api is protected against multiple close 55 | try { 56 | mergingIterator.close(); 57 | } 58 | finally { 59 | cleanup.run(); 60 | } 61 | } 62 | 63 | @Override 64 | public boolean valid() 65 | { 66 | return mergingIterator.valid(); 67 | } 68 | 69 | @Override 70 | public boolean seekToFirst() 71 | { 72 | return mergingIterator.seekToFirst(); 73 | } 74 | 75 | @Override 76 | public boolean seekToLast() 77 | { 78 | return mergingIterator.seekToLast(); 79 | } 80 | 81 | @Override 82 | public boolean seek(InternalKey targetKey) 83 | { 84 | return mergingIterator.seek(targetKey); 85 | } 86 | 87 | @Override 88 | public boolean next() 89 | { 90 | return mergingIterator.next(); 91 | } 92 | 93 | @Override 94 | public boolean prev() 95 | { 96 | return mergingIterator.prev(); 97 | } 98 | 99 | @Override 100 | public InternalKey key() 101 | { 102 | return mergingIterator.key(); 103 | } 104 | 105 | @Override 106 | public Slice value() 107 | { 108 | return mergingIterator.value(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /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.google.common.base.Preconditions.checkState; 24 | import static org.iq80.leveldb.impl.SequenceNumber.MAX_SEQUENCE_NUMBER; 25 | 26 | public class InternalUserComparator 27 | implements UserComparator 28 | { 29 | private final InternalKeyComparator internalKeyComparator; 30 | 31 | public InternalUserComparator(InternalKeyComparator internalKeyComparator) 32 | { 33 | this.internalKeyComparator = internalKeyComparator; 34 | } 35 | 36 | @Override 37 | public int compare(Slice left, Slice right) 38 | { 39 | return internalKeyComparator.compare(new InternalKey(left), new InternalKey(right)); 40 | } 41 | 42 | @Override 43 | public String name() 44 | { 45 | return internalKeyComparator.name(); 46 | } 47 | 48 | @Override 49 | public Slice findShortestSeparator( 50 | Slice start, 51 | Slice limit) 52 | { 53 | // Attempt to shorten the user portion of the key 54 | Slice startUserKey = new InternalKey(start).getUserKey(); 55 | Slice limitUserKey = new InternalKey(limit).getUserKey(); 56 | 57 | Slice shortestSeparator = internalKeyComparator.getUserComparator().findShortestSeparator(startUserKey, limitUserKey); 58 | 59 | if (internalKeyComparator.getUserComparator().compare(startUserKey, shortestSeparator) < 0) { 60 | // User key has become larger. Tack on the earliest possible 61 | // number to the shortened user key. 62 | InternalKey newInternalKey = new InternalKey(shortestSeparator, MAX_SEQUENCE_NUMBER, ValueType.VALUE); 63 | checkState(compare(start, newInternalKey.encode()) < 0); // todo 64 | checkState(compare(newInternalKey.encode(), limit) < 0); // todo 65 | 66 | return newInternalKey.encode(); 67 | } 68 | 69 | return start; 70 | } 71 | 72 | @Override 73 | public Slice findShortSuccessor(Slice key) 74 | { 75 | Slice userKey = new InternalKey(key).getUserKey(); 76 | Slice shortSuccessor = internalKeyComparator.getUserComparator().findShortSuccessor(userKey); 77 | 78 | if (internalKeyComparator.getUserComparator().compare(userKey, shortSuccessor) < 0) { 79 | // User key has become larger. Tack on the earliest possible 80 | // number to the shortened user key. 81 | InternalKey newInternalKey = new InternalKey(shortSuccessor, MAX_SEQUENCE_NUMBER, ValueType.VALUE); 82 | checkState(compare(key, newInternalKey.encode()) < 0); // todo 83 | 84 | return newInternalKey.encode(); 85 | } 86 | 87 | return key; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /leveldb/src/test/java/org/iq80/leveldb/memenv/MemFileTest.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.memenv; 19 | 20 | import org.testng.Assert; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.Collections; 24 | 25 | import static org.testng.Assert.assertEquals; 26 | import static org.testng.Assert.assertFalse; 27 | import static org.testng.Assert.assertNotEquals; 28 | 29 | public class MemFileTest 30 | { 31 | @Test 32 | public void testEquals() 33 | { 34 | MemFs fs = new MemFs(); 35 | MemFile ab = MemFile.createMemFile(fs, "/a/b"); 36 | MemFile abParent = ab.getParentFile(); 37 | MemFile a = MemFile.createMemFile(new MemFs(), "/a"); 38 | MemFile ab1 = MemFile.createMemFile(new MemFs(), "/a").child("b"); 39 | MemFile ab1Parent = ab1.getParentFile(); 40 | 41 | assertEqualsFile(ab, ab1); 42 | assertEqualsFile(abParent, ab1Parent); 43 | assertEqualsFile(abParent, a); 44 | assertEqualsFile(ab, MemFile.createMemFile(new MemFs(), "/a/b/")); 45 | assertEqualsFile(ab, MemFile.createMemFile(new MemFs(), "a/b/")); 46 | 47 | assertNotEquals(ab, a); 48 | assertNotEquals(ab, MemFile.createMemFile(fs, "/a/e")); 49 | assertNotEquals(ab, MemFile.createMemFile(fs, "/")); 50 | assertNotEquals(ab.hashCode(), a.hashCode()); 51 | assertNotEquals(ab1.hashCode(), a.hashCode()); 52 | assertNotEquals(ab, a); 53 | } 54 | 55 | @Test 56 | public void testParent() 57 | { 58 | MemFs fs = new MemFs(); 59 | MemFile ab = MemFile.createMemFile(fs, "/a/b/c"); 60 | MemFile p = ab.getParentFile(); 61 | assertEqualsFile(p, MemFile.createMemFile(fs, "/a/b")); 62 | p = p.getParentFile(); 63 | assertEqualsFile(p, MemFile.createMemFile(fs, "/a")); 64 | p = p.getParentFile(); 65 | assertEqualsFile(p, MemFile.createMemFile(fs, "/")); 66 | p = p.getParentFile(); 67 | assertEqualsFile(p, MemFile.createMemFile(fs, "/")); 68 | } 69 | 70 | @Test 71 | public void testDefault() 72 | { 73 | MemFile ab = MemFile.createMemFile(new MemFs(), "/a/b"); 74 | assertEquals(ab.getName(), "b"); 75 | assertEquals(ab.getPath(), "/a/b"); 76 | assertFalse(ab.isDirectory()); 77 | assertFalse(ab.isFile()); 78 | assertFalse(ab.exists()); 79 | assertEquals(ab.listFiles(), Collections.emptyList()); 80 | Assert.assertThrows(() -> ab.child("/invalid")); 81 | } 82 | 83 | private static void assertEqualsFile(MemFile f1, MemFile f2) 84 | { 85 | assertEquals(f1, f2); 86 | assertEquals(f1.getName(), f2.getName()); 87 | assertEquals(f1.getPath(), f2.getPath()); 88 | assertEquals(f1.isFile(), f2.isFile()); 89 | assertEquals(f1.isDirectory(), f2.isDirectory()); 90 | assertEquals(f1.exists(), f2.exists()); 91 | assertEquals(f1.getParentFile(), f2.getParentFile()); 92 | assertEquals(f1.hashCode(), f2.hashCode()); 93 | } 94 | } 95 | --------------------------------------------------------------------------------