Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,25 @@ object RasterSource extends LazyLogging {
/** A RasterFrames RasterSource which delegates most operations to a geotrellis-contrib RasterSource */
abstract class DelegatingRasterSource(source: URI, delegateBuilder: () => GTRasterSource) extends RasterSource with URIRasterSource {
@transient
lazy val delegate = delegateBuilder()
@volatile
private var _delRef: GTRasterSource = _

private def retryableRead[R >: Null](f: GTRasterSource => R): R = synchronized {
try {
if (_delRef == null)
_delRef = delegateBuilder()
f(_delRef)
}
catch {
// On this exeception we attempt to recreate the delegate and read again.
case be: java.nio.BufferUnderflowException =>
_delRef = null
val newDel = delegateBuilder()
val result = f(newDel)
_delRef = newDel
result
}
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the tricky bit. Need to make sure it's thread safe, even though multiple threads "shouldn't" be calling the read code.


// Bad, bad, bad?
override def equals(obj: Any): Boolean = obj match {
Expand All @@ -201,16 +219,16 @@ object RasterSource extends LazyLogging {
override def hashCode(): Int = source.hashCode()

// This helps reduce header reads between serializations
lazy val info: SimpleGeoTiffInfo = {
lazy val info: SimpleGeoTiffInfo = retryableRead { rs =>
SimpleGeoTiffInfo(
delegate.cols,
delegate.rows,
delegate.cellType,
delegate.extent,
delegate.rasterExtent,
delegate.crs,
rs.cols,
rs.rows,
rs.cellType,
rs.extent,
rs.rasterExtent,
rs.crs,
fetchTags,
delegate.bandCount,
rs.bandCount,
None
)
}
Expand All @@ -221,21 +239,49 @@ object RasterSource extends LazyLogging {
override def extent: Extent = info.extent
override def cellType: CellType = info.cellType
override def bandCount: Int = info.bandCount
private def fetchTags: Tags = delegate match {
private def fetchTags: Tags = retryableRead {
case rs: GeoTiffRasterSource => rs.tiff.tags
case _ => EMPTY_TAGS
}
override def tags: Tags = info.tags

// private def readWithRetry[R >: Null](f: () => R): R = {
// val retryLimit = 10
// var result: R = null
// var cnt = 0
// while(result == null && cnt < retryLimit) {
// cnt = cnt + 1
// try {
// result = f()
// }
// catch {
// case be: java.nio.BufferUnderflowException =>
// if (cnt == 1)
// logger.warn("Retrying read to " + source)
// if (cnt == retryLimit) {
// logger.warn(s"Failed to read '$source' after $cnt tries")
// throw be
// }
// else Thread.sleep(100)
// ()
// }
// }
// result
// }


Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that comment block. Will get rid of eventually.

override protected def readBounds(bounds: Traversable[GridBounds], bands: Seq[Int]): Iterator[Raster[MultibandTile]] =
delegate.readBounds(bounds, bands)
retryableRead(_.readBounds(bounds, bands))

override def read(bounds: GridBounds, bands: Seq[Int]): Raster[MultibandTile] =
delegate
.read(bounds, bands)
retryableRead(_.read(bounds, bands)
.getOrElse(throw new IllegalArgumentException(s"Bounds '$bounds' outside of source"))
)

override def read(extent: Extent, bands: Seq[Int]): Raster[MultibandTile] =
delegate
.read(extent, bands)
retryableRead(_.read(extent, bands)
.getOrElse(throw new IllegalArgumentException(s"Extent '$extent' outside of source"))
)
}

case class JVMGeoTiffRasterSource(source: URI) extends DelegatingRasterSource(source, () => GeoTiffRasterSource(source.toASCIIString))
Expand Down