blob: 5863b007b8b3650c0d0c50763436001f797c09db [file] [log] [blame]
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.baidu.hugegraph.computer.core.store.file.hgkvfile;
import java.io.File;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import com.baidu.hugegraph.computer.core.common.exception.ComputerException;
import com.baidu.hugegraph.computer.core.io.IOFactory;
import com.baidu.hugegraph.computer.core.io.RandomAccessInput;
import com.baidu.hugegraph.computer.core.io.RandomAccessOutput;
import com.baidu.hugegraph.util.E;
public class HgkvFileImpl extends AbstractHgkvFile {
public HgkvFileImpl(String path) {
super(path);
}
public static HgkvFile create(String path) throws IOException {
File file = new File(path);
E.checkArgument(!file.exists(),
"Can't create HgkvFile because the " +
"file already exists: '%s'", file.getPath());
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
file.createNewFile();
return new HgkvFileImpl(path);
}
public static HgkvFile open(String path) throws IOException {
E.checkArgumentNotNull(path, "Parameter path can't be null");
return open(new File(path));
}
public static HgkvFile open(File file) throws IOException {
E.checkArgumentNotNull(file, "Parameter file can't be null");
E.checkArgument(file.exists(),
"Failed to open path because the " +
"file does not exists: '%s'", file.getPath());
E.checkArgument(file.isFile(),
"Failed to open path because it's not a file: '%s'",
file.getPath());
HgkvFileImpl hgkvFile = new HgkvFileImpl(file.getPath());
hgkvFile.readFooter();
return hgkvFile;
}
private static String version(short majorVersion, short minorVersion) {
return StringUtils.join(majorVersion, ".", minorVersion);
}
@Override
public RandomAccessOutput output() throws IOException {
return IOFactory.createFileOutput(new File(this.path));
}
@Override
public void close() throws IOException {
// pass
}
private void readFooter() throws IOException {
File file = new File(this.path);
// The footerLength occupied 4 bytes, versionLength 2 * 2 bytes
long versionOffset = file.length() - Short.BYTES * 2 - Integer.BYTES;
try (RandomAccessInput input = IOFactory.createFileInput(file)) {
input.seek(versionOffset);
// Read version
short majorVersion = input.readShort();
short minorVersion = input.readShort();
String version = version(majorVersion, minorVersion);
// Read footerLength
int footerLength = input.readFixedInt();
switch (version) {
case "1.0":
this.readFooterV1d0(input, file.length() - footerLength);
break;
default:
throw new ComputerException("Illegal HgkvFile version '%s'",
version);
}
}
}
private void readFooterV1d0(RandomAccessInput input, long footerBegin)
throws IOException {
input.seek(footerBegin);
// Read magic
String magic = new String(input.readBytes(MAGIC.length()));
E.checkArgument(MAGIC.equals(magic),
"Failed to read footer, illegal hgvk-file magic in " +
"file: '%s'", this.path);
this.magic = magic;
// Read numEntries
this.numEntries = input.readLong();
// Read numSubEntries
this.numSubEntries = input.readLong();
// Read dataBlock length
this.dataBlockSize = input.readLong();
// Read indexBlock length
this.indexBlockSize = input.readLong();
// Read max key and min key
long maxKeyOffset = input.readLong();
long minKeyOffset = input.readLong();
// Read version
short majorVersion = input.readShort();
short minorVersion = input.readShort();
this.version = version(majorVersion, minorVersion);
if (this.numEntries > 0) {
// Read max key
input.seek(maxKeyOffset);
int maxKeyLength = input.readFixedInt();
this.max = input.readBytes(maxKeyLength);
// Read min Key
input.seek(minKeyOffset);
int minKeyLength = input.readFixedInt();
this.min = input.readBytes(minKeyLength);
}
}
}