Skip to content

Commit

Permalink
Remove dependency on long, abortable-promise-cache (#128)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin authored Aug 30, 2024
1 parent 4f68d30 commit 61791ba
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 158 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"esm"
],
"scripts": {
"test": "vitest run",
"test": "vitest",
"lint": "eslint --report-unused-disable-directives --max-warnings 0",
"format": "prettier --write .",
"docs": "documentation readme --shallow src/indexedCramFile.ts --section=IndexedCramFile; documentation readme --shallow src/cramFile/file.ts --section=CramFile; documentation readme --shallow src/craiIndex.ts --section=CraiIndex; documentation readme --shallow errors.ts '--section=Exception Classes'; documentation readme --shallow src/cramFile/file.ts --section=CramFile; documentation readme --shallow src/cramFile/record.ts --section=CramRecord",
Expand All @@ -31,7 +31,7 @@
"build:es5": "tsc --target es2015 --module commonjs --outDir dist",
"build": "npm run build:esm && npm run build:es5",
"postbuild": "webpack",
"prepack": "npm test && npm run build && cp dist/errors.js errors.js",
"prepack": "npm test run && npm run build && cp dist/errors.js errors.js",
"postpublish": "rm errors.js",
"postversion": "git push --follow-tags"
},
Expand Down
34 changes: 19 additions & 15 deletions src/craiIndex.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import AbortablePromiseCache from '@gmod/abortable-promise-cache'
import QuickLRU from 'quick-lru'
import { unzip } from './unzip'
import { open } from './io'
import { CramMalformedError } from './errors'
Expand Down Expand Up @@ -35,6 +33,13 @@ function addRecordToIndex(index: ParsedIndex, record: number[]) {
})
}

function maybeUnzip(data: Buffer) {
if (data[0] === 31 && data[1] === 139) {
return unzip(data)
}
return data
}

export default class CraiIndex {
// A CRAM index (.crai) is a gzipped tab delimited file containing the
// following columns:
Expand All @@ -45,10 +50,9 @@ export default class CraiIndex {
// 4. Container start byte position in the file
// 5. Slice start byte position in the container data (‘blocks’)
// 6. Slice size in bytes
//
// Each line represents a slice in the CRAM file. Please note that all slices
// must be listed in index file.
private _parseCache: AbortablePromiseCache<unknown, ParsedIndex>
// Each line represents a slice in the CRAM file. Please note that all slices must be listed in index file.
private parseIndexP?: Promise<ParsedIndex>

private filehandle: Filehandle

/**
Expand All @@ -60,17 +64,11 @@ export default class CraiIndex {
*/
constructor(args: CramFileSource) {
this.filehandle = open(args.url, args.path, args.filehandle)
this._parseCache = new AbortablePromiseCache<unknown, ParsedIndex>({
cache: new QuickLRU({ maxSize: 1 }),
fill: (_data, _signal) => this.parseIndex(),
})
}

async parseIndex() {
const index: ParsedIndex = {}
const data = await this.filehandle.readFile()
const uncompressedBuffer =
data[0] === 31 && data[1] === 139 ? unzip(data) : data
const uncompressedBuffer = maybeUnzip(await this.filehandle.readFile())
if (
uncompressedBuffer.length > 4 &&
uncompressedBuffer.readUInt32LE(0) === BAI_MAGIC
Expand Down Expand Up @@ -122,8 +120,14 @@ export default class CraiIndex {
return index
}

getIndex(opts: { signal?: AbortSignal } = {}) {
return this._parseCache.get('index', null, opts.signal)
getIndex() {
if (!this.parseIndexP) {
this.parseIndexP = this.parseIndex().catch((e: unknown) => {
this.parseIndexP = undefined
throw e
})
}
return this.parseIndexP
}

/**
Expand Down
7 changes: 3 additions & 4 deletions src/cramFile/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,9 @@ export default class CramFile {
cacheSize: args.cacheSize ?? 20000,
}

// cache of features in a slice, keyed by the
// slice offset. caches all of the features in a slice, or none.
// the cache is actually used by the slice object, it's just
// kept here at the level of the file
// cache of features in a slice, keyed by the slice offset. caches all of
// the features in a slice, or none. the cache is actually used by the
// slice object, it's just kept here at the level of the file
this.featureCache = new QuickLRU({
maxSize: this.options.cacheSize,
})
Expand Down
15 changes: 7 additions & 8 deletions src/cramFile/slice/decodeRecord.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Long from 'long'
import { CramMalformedError } from '../../errors'
import {
BamFlagsDecoder,
Expand Down Expand Up @@ -31,7 +30,7 @@ function readNullTerminatedString(buffer: Uint8Array) {
* parse a BAM tag's array value from a binary buffer
* @private
*/
function parseTagValueArray(buffer: Buffer) {
function parseTagValueArray(buffer: Uint8Array) {
const arrayType = String.fromCharCode(buffer[0]!)
const length = Int32Array.from(buffer.slice(1))[0]!

Expand Down Expand Up @@ -80,15 +79,15 @@ function parseTagValueArray(buffer: Buffer) {
return array
}

function parseTagData(tagType: string, buffer: any) {
function parseTagData(tagType: string, buffer: Uint8Array) {
if (tagType === 'Z') {
return readNullTerminatedString(buffer)
}
if (tagType === 'A') {
return String.fromCharCode(buffer[0])
return String.fromCharCode(buffer[0]!)
}
if (tagType === 'I') {
return Long.fromBytesLE(buffer).toNumber()
return new Uint32Array(buffer.buffer)[0]
}
if (tagType === 'i') {
return new Int32Array(buffer.buffer)[0]
Expand All @@ -103,7 +102,7 @@ function parseTagData(tagType: string, buffer: any) {
return new Int8Array(buffer.buffer)[0]
}
if (tagType === 'C') {
return buffer[0] as number
return buffer[0]!
}
if (tagType === 'f') {
return new Float32Array(buffer.buffer)[0]
Expand Down Expand Up @@ -313,7 +312,6 @@ export default function decodeRecord(
// TN = tag names
const TN = compressionScheme.getTagNames(TLindex)!
const ntags = TN.length

for (let i = 0; i < ntags; i += 1) {
const tagId = TN[i]!
const tagName = tagId.slice(0, 2)
Expand All @@ -322,7 +320,8 @@ export default function decodeRecord(
const tagData = compressionScheme
.getCodecForTag(tagId)
.decode(slice, coreDataBlock, blocksByContentId, cursors)
tags[tagName] = parseTagData(tagType, tagData)
tags[tagName] =
typeof tagData === 'number' ? tagData : parseTagData(tagType, tagData)
}

let readFeatures: ReadFeature[] | undefined
Expand Down
2 changes: 1 addition & 1 deletion src/cramFile/slice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export default class CramSlice {
constructor(
public container: CramContainer,
public containerPosition: number,
_unused: number,
public sliceSize: number,
) {
this.file = container.file
}
Expand Down
Loading

0 comments on commit 61791ba

Please sign in to comment.