Fix issue with in browser Hash (#1738)

Also, make Hash not copy the bytes.
This commit is contained in:
Erik Arvidsson
2016-06-06 17:11:34 -07:00
parent bc9f9d19e1
commit 4af0ca1efb
7 changed files with 22 additions and 13 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "@attic/noms",
"license": "Apache-2.0",
"version": "44.0.0",
"version": "44.0.1",
"description": "Noms JS SDK",
"repository": "https://github.com/attic-labs/noms",
"main": "dist/commonjs/noms.js",

View File

@@ -10,6 +10,7 @@ import Rusha from 'rusha';
const r = new Rusha();
export default function sha1(data: Uint8Array): Uint32Array {
return r.rawDigest(data);
export default function sha1(data: Uint8Array): Uint8Array {
const ta = r.rawDigest(data);
return new Uint8Array(ta.buffer, ta.byteOffset, ta.byteLength);
}

View File

@@ -101,7 +101,8 @@ function deserializeHints(buffer: ArrayBuffer): {hints: Array<Hash>, offset: num
for (; offset < totalLength;) {
invariant(buffer.byteLength - offset >= sha1Size, 'Invalid hint buffer');
const hashArray = new Uint8Array(buffer, offset, sha1Size);
// Make a slice/copy of the ArrayBuffer to prevent `buffer` from being gc'ed.
const hashArray = new Uint8Array(buffer.slice(offset, offset + sha1Size));
const hash = new Hash(hashArray);
offset += sha1Size;
@@ -118,6 +119,7 @@ export function deserializeChunks(buffer: ArrayBuffer, offset: number = 0): Arra
for (; offset < totalLenth;) {
invariant(buffer.byteLength - offset >= chunkHeaderSize, 'Invalid chunk buffer');
// No need to copy the data out since we are not holding on to the hash object.
const hashArray = new Uint8Array(buffer, offset, sha1Size);
const hash = new Hash(hashArray);
offset += sha1Size;
@@ -128,9 +130,8 @@ export function deserializeChunks(buffer: ArrayBuffer, offset: number = 0): Arra
invariant(offset + chunkLength <= totalLenth, 'Invalid chunk buffer');
const dataArray = new Uint8Array(buffer, offset, chunkLength);
const chunk = new Chunk(new Uint8Array(dataArray)); // Makes a slice (copy) of the byte sequence
// from buffer.
// Make a copy of the data so that buffer can be collected.
const chunk = new Chunk(new Uint8Array(buffer.slice(offset, offset + chunkLength)));
invariant(chunk.hash.equals(hash), 'Serialized hash !== computed hash');

View File

@@ -128,7 +128,8 @@ export class BinaryNomsReader {
}
readHash(): Hash {
const digest = new Uint8Array(this.buff, this.offset, sha1Size);
// Make a copy of the data.
const digest = new Uint8Array(this.buff.slice(this.offset, this.offset + sha1Size));
this.offset += sha1Size;
return new Hash(digest);
}

View File

@@ -34,9 +34,12 @@ function sha1ToUint8Array(s: string): Uint8Array {
export default class Hash {
_digest: Uint8Array;
/**
* The Hash instance does not copy the `digest` so if the `digest` is part of a large ArrayBuffer
* the caller might want to make a copy first to prevent that ArrayBuffer from being retained.
*/
constructor(digest: Uint8Array) {
// Make a copy to prevent holding on to the data that was passed in.
this._digest = new Uint8Array(digest);
this._digest = digest;
}
get digest(): Uint8Array {

View File

@@ -3,7 +3,7 @@
"license": "Apache-2.0",
"devDependencies": {
"@attic/eslintrc": "^3.1.0",
"@attic/noms": "^42.0.0",
"@attic/noms": "file:../../../js/",
"@attic/webpack-config": "^2.1.0",
"babel-cli": "6.6.5",
"babel-core": "6.7.2",

View File

@@ -65,13 +65,15 @@ function load() {
const httpStore = new HttpBatchStore(params.db, undefined, opts);
database = new Database(httpStore);
const setRootHash = hash => {
const setRootHash = (hash: Hash) => {
rootHash = hash;
handleChunkLoad(hash, hash);
};
if (params.hash) {
setRootHash(Hash.parse(params.ref));
const hash = Hash.parse(params.ref);
invariant(hash);
setRootHash(hash);
} else {
httpStore.getRoot().then(setRootHash);
}
@@ -227,6 +229,7 @@ function handleNodeClick(e: MouseEvent, id: string) {
render();
} else {
const hash = Hash.parse(id);
invariant(hash);
database.readValue(hash).then(value => {
handleChunkLoad(hash, value, id);
});