@@ -41,18 +41,19 @@ class JobSqlDAO(config: Config) extends JobDAO with FileCacher {
41
41
42
42
// Definition of the tables
43
43
// scalastyle:off
44
- class Binaries (tag : Tag ) extends Table [(Int , String , String , Timestamp )](tag, " BINARIES" ) {
44
+ class Binaries (tag : Tag ) extends Table [(Int , String , String , Timestamp , Array [ Byte ] )](tag, " BINARIES" ) {
45
45
def binId = column[Int ](" BIN_ID" , O .PrimaryKey , O .AutoInc )
46
46
def appName = column[String ](" APP_NAME" )
47
47
def binaryType = column[String ](" BINARY_TYPE" )
48
48
def uploadTime = column[Timestamp ](" UPLOAD_TIME" )
49
- def * = (binId, appName, binaryType, uploadTime)
49
+ def binHash = column[Array [Byte ]](" BIN_HASH" )
50
+ def * = (binId, appName, binaryType, uploadTime, binHash)
50
51
}
51
52
52
- class BinariesContents (tag : Tag ) extends Table [(Int , Blob )](tag, " BINARIES_CONTENTS" ) {
53
- def binId = column[Int ]( " BIN_ID " , O .PrimaryKey )
53
+ class BinariesContents (tag : Tag ) extends Table [(Array [ Byte ] , Blob )](tag, " BINARIES_CONTENTS" ) {
54
+ def binHash = column[Array [ Byte ]]( " BIN_HASH " , O .PrimaryKey )
54
55
def binary = column[Blob ](" BINARY" )
55
- def * = (binId , binary)
56
+ def * = (binHash , binary)
56
57
}
57
58
58
59
val binaries = TableQuery [Binaries ]
@@ -183,12 +184,24 @@ class JobSqlDAO(config: Config) extends JobDAO with FileCacher {
183
184
Await .result(db.run(query), 60 seconds)
184
185
}
185
186
187
+ private def calculateBinaryHash (binBytes : Array [Byte ]): Array [Byte ] = {
188
+ import java .security .MessageDigest
189
+ val md = MessageDigest .getInstance(" SHA-256" );
190
+ md.digest(binBytes)
191
+ }
192
+
186
193
// Insert JarInfo and its jar into db and return the primary key associated with that row
187
194
private def insertBinaryInfo (binInfo : BinaryInfo , binBytes : Array [Byte ]): Future [Int ] = {
195
+ val hash = calculateBinaryHash(binBytes);
188
196
val dbAction = (for {
189
197
binId <- binaries.returning(binaries.map(_.binId)) +=
190
- (- 1 , binInfo.appName, binInfo.binaryType.name, convertDateJodaToSql(binInfo.uploadTime))
191
- _ <- binariesContents.map(bc => bc.* ) += (binId, new SerialBlob (binBytes))
198
+ (- 1 , binInfo.appName, binInfo.binaryType.name, convertDateJodaToSql(binInfo.uploadTime), hash)
199
+ _ <- binariesContents.filter(_.binHash === hash).result.headOption.flatMap{
200
+ case None =>
201
+ binariesContents.map(bc => bc.* ) += (hash, new SerialBlob (binBytes))
202
+ case Some (bc) =>
203
+ DBIO .successful(None ) // no-op
204
+ }
192
205
} yield binId).transactionally
193
206
db.run(dbAction)
194
207
}
@@ -200,9 +213,15 @@ class JobSqlDAO(config: Config) extends JobDAO with FileCacher {
200
213
201
214
private def deleteBinaryInfo (appName : String ): Future [Int ] = {
202
215
val deleteBinary = binaries.filter(_.appName === appName)
203
- val deleteBinariesContents = binariesContents.filter(_.binId in deleteBinary.map(_.binId))
216
+ val hashUsed = binaries.filter(_.binHash in deleteBinary.map(_.binHash)).filter(_.appName =!= appName)
217
+ val deleteBinariesContents = binariesContents.filter(_.binHash in deleteBinary.map(_.binHash))
204
218
val dbAction = (for {
205
- _ <- deleteBinariesContents.delete
219
+ _ <- hashUsed.result.headOption.flatMap{
220
+ case None =>
221
+ deleteBinariesContents.delete
222
+ case Some (bc) =>
223
+ DBIO .successful(None ) // no-op
224
+ }
206
225
b <- deleteBinary.delete
207
226
} yield b).transactionally
208
227
db.run(dbAction).recover(logDeleteErrors)
@@ -231,7 +250,7 @@ class JobSqlDAO(config: Config) extends JobDAO with FileCacher {
231
250
b <- binaries.filter { bin =>
232
251
bin.appName === appName && bin.uploadTime === dateTime && bin.binaryType === binaryType.name
233
252
}
234
- bc <- binariesContents if b.binId === bc.binId
253
+ bc <- binariesContents if b.binHash === bc.binHash
235
254
} yield bc.binary
236
255
val dbAction = query.result
237
256
db.run(dbAction.head.map { b => b.getBytes(1 , b.length.toInt) }.transactionally)
0 commit comments