Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: chore: use existing open file in Frame Helper #1199

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions hive/lib/src/backend/vm/storage_backend_vm.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';

import 'package:hive/hive.dart';
Expand Down Expand Up @@ -38,7 +39,7 @@ class StorageBackendVm extends StorageBackend {

/// Not part of public API
@visibleForTesting
late RandomAccessFile lockRaf;
RandomAccessFile? lockRaf;

/// Not part of public API
@visibleForTesting
Expand Down Expand Up @@ -78,28 +79,39 @@ class StorageBackendVm extends StorageBackend {
TypeRegistry registry, Keystore keystore, bool lazy) async {
this.registry = registry;

lockRaf = await _lockFile.open(mode: FileMode.write);
if ((Hive as HiveImpl).useLocks) {
final lockRaf = this.lockRaf = await _lockFile.open(mode: FileMode.write);
await lockRaf.lock();
}

int recoveryOffset;
if (!lazy) {
recoveryOffset =
await _frameHelper.framesFromFile(path, keystore, registry, _cipher);
} else {
recoveryOffset = await _frameHelper.keysFromFile(path, keystore, _cipher);
}

if (recoveryOffset != -1) {
if (_crashRecovery) {
print('Recovering corrupted box.');
await writeRaf.truncate(recoveryOffset);
await writeRaf.setPosition(recoveryOffset);
writeOffset = recoveryOffset;
try {
int recoveryOffset;
if (!lazy) {
recoveryOffset = await _frameHelper.framesFromFile(
readRaf, keystore, registry, _cipher);
} else {
throw HiveError('Wrong checksum in hive file. Box may be corrupted.');
recoveryOffset =
await _frameHelper.keysFromFile(readRaf, keystore, _cipher);
}

if (recoveryOffset != -1) {
if (_crashRecovery) {
print('Recovering corrupted box.');
await writeRaf.truncate(recoveryOffset);
await writeRaf.setPosition(recoveryOffset);
writeOffset = recoveryOffset;
} else {
throw HiveError('Wrong checksum in hive file. Box may be corrupted.');
}
}
} catch (e, s) {
log(
'Error checking hive recovery offset',
error: e,
stackTrace: s,
name: 'hive',
);
rethrow;
}
}

Expand Down Expand Up @@ -217,8 +229,10 @@ class StorageBackendVm extends StorageBackend {
await readRaf.close();
await writeRaf.close();

await lockRaf.close();
await _lockFile.delete();
await lockRaf?.close();
if (await _lockFile.exists()) {
await _lockFile.delete();
}
}

@override
Expand Down
41 changes: 26 additions & 15 deletions hive/lib/src/io/frame_io_helper.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

Expand All @@ -12,34 +13,44 @@ import 'package:meta/meta.dart';
/// Not part of public API
class FrameIoHelper extends FrameHelper {
/// Not part of public API
///
/// helps allowing to override this method in tests
@visibleForTesting
Future<RandomAccessFile> openFile(String path) {
return File(path).open();
FutureOr<RandomAccessFile> overridableRAF(RandomAccessFile raf) {
return raf;
}

/// Not part of public API
///
/// helps allowing to override this method in tests
@visibleForTesting
Future<List<int>> readFile(String path) {
return File(path).readAsBytes();
Future<Uint8List> overridableReadFile(RandomAccessFile raf) async {
final previousPosition = await raf.position(); // likely 0 in any case

final length = await raf.length();
final bytes = await raf.read(length);

await raf.setPosition(previousPosition);

return bytes;
}

/// Not part of public API
Future<int> keysFromFile(
String path, Keystore keystore, HiveCipher? cipher) async {
var raf = await openFile(path);
var fileReader = BufferedFileReader(raf);
try {
return await _KeyReader(fileReader).readKeys(keystore, cipher);
} finally {
await raf.close();
}
RandomAccessFile raf, Keystore keystore, HiveCipher? cipher) async {
// only used for testing override
final file = await overridableRAF(raf);
final fileReader = BufferedFileReader(file);

return await _KeyReader(fileReader).readKeys(keystore, cipher);
}

/// Not part of public API
Future<int> framesFromFile(String path, Keystore keystore,
Future<int> framesFromFile(RandomAccessFile raf, Keystore keystore,
TypeRegistry registry, HiveCipher? cipher) async {
var bytes = await readFile(path);
return framesFromBytes(bytes as Uint8List, keystore, registry, cipher);
// only used for testing override
final bytes = await overridableReadFile(raf);
return framesFromBytes(bytes, keystore, registry, cipher);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'package:hive/src/binary/frame.dart';
import 'package:hive/src/registry/type_registry_impl.dart';
import 'package:test/test.dart';


void main() {
group('RandomAccessBuffer', () {
test('empty random access buffer', () {
Expand Down
3 changes: 1 addition & 2 deletions hive/test/tests/backend/vm/storage_backend_vm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,7 @@ void main() {
.thenAnswer((i) => Future.value(writeRaf));
when(() => writeRaf.writeFrom(bytes))
.thenAnswer((i) => Future.value(writeRaf));
when(() => writeRaf.flush())
.thenAnswer((i) => Future.value(writeRaf));
when(() => writeRaf.flush()).thenAnswer((i) => Future.value(writeRaf));

var backend = _getBackend(writeRaf: writeRaf)
// The registry needs to be initialized before writing values, and
Expand Down
18 changes: 9 additions & 9 deletions hive/test/tests/io/frame_io_helper_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ class _FrameIoHelperTest extends FrameIoHelper {
_FrameIoHelperTest(this.bytes);

@override
Future<RandomAccessFile> openFile(String path) async {
Future<RandomAccessFile> overridableRAF(RandomAccessFile raf) async {
return getTempRaf(bytes);
}

@override
Future<Uint8List> readFile(String path) async {
Future<Uint8List> overridableReadFile(RandomAccessFile raf) async {
return bytes;
}
}
Expand All @@ -39,8 +39,8 @@ void main() {
test('frame', () async {
var keystore = Keystore.debug();
var ioHelper = _FrameIoHelperTest(_getBytes(frameBytes));
var recoveryOffset =
await ioHelper.keysFromFile('null', keystore, null);
var recoveryOffset = await ioHelper.keysFromFile(
await getTempRaf(const []), keystore, null);
expect(recoveryOffset, -1);

var testKeystore = Keystore.debug(
Expand All @@ -53,8 +53,8 @@ void main() {
test('encrypted', () async {
var keystore = Keystore.debug();
var ioHelper = _FrameIoHelperTest(_getBytes(frameBytesEncrypted));
var recoveryOffset =
await ioHelper.keysFromFile('null', keystore, testCipher);
var recoveryOffset = await ioHelper.keysFromFile(
await getTempRaf(const []), keystore, testCipher);
expect(recoveryOffset, -1);

var testKeystore = Keystore.debug(
Expand All @@ -73,8 +73,8 @@ void main() {
test('frame', () async {
var keystore = Keystore.debug();
var ioHelper = _FrameIoHelperTest(_getBytes(frameBytes));
var recoveryOffset =
await ioHelper.framesFromFile('null', keystore, testRegistry, null);
var recoveryOffset = await ioHelper.framesFromFile(
await getTempRaf(const []), keystore, testRegistry, null);
expect(recoveryOffset, -1);

var testKeystore = Keystore.debug(
Expand All @@ -88,7 +88,7 @@ void main() {
var keystore = Keystore.debug();
var ioHelper = _FrameIoHelperTest(_getBytes(frameBytesEncrypted));
var recoveryOffset = await ioHelper.framesFromFile(
'null', keystore, testRegistry, testCipher);
await getTempRaf(const []), keystore, testRegistry, testCipher);
expect(recoveryOffset, -1);

var testKeystore = Keystore.debug(
Expand Down