Skip to content

Commit

Permalink
Handle malformed db entries (#87)
Browse files Browse the repository at this point in the history
* Catch errors likely caused by null paths in db

The errors caused by reading the db when a location with no path set
has got into the database are actually `[InvalidCastException]`s thrown
when trying to convert the identifiers from the database into strings
for `[Location]`s.

This is caused by entries inserted with no path calling `GetById($null)`
so they get the 0-parameter version,
https://github.com/mbdavid/LiteDB/blob/f7ee275908ca48156a9d0bed054809955843e4b0/LiteDB/Document/BsonValue.cs#L49

Restricting the `catch{}` to `[IOException]` also means it's possible to
handle the file in use errors the retry logic is supposed to be
handling separately to other types of error.

* Move database retry logic inside catch block

Should result in more understandable error messages than using
`$Error[0]` and sometimes failing. Plus, will only trigger for
`IOException`s, which is what the file locked errors are reported
as.

* Check for and remove problem entries in db

If an `InvalidCastException` is encountered when running `DBFind`,
run a query to check for entries that look abnormal and remove them
from the database if found.

* Add mandatory params to ZLocation.psd1 exports

* Add mandatory params to ZLocation.Storage

* Add mandatory parameters to ZLocation.Service

`Add` and `Remove` could really use them, but can't add param blocks
to class methods.

* Add mandatory parameters to ZLocation.Search

* Add mandatory parameters for IsExactMatch
  • Loading branch information
theaquamarine authored and vors committed Sep 9, 2019
1 parent fd4b953 commit f6b093c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 17 deletions.
26 changes: 20 additions & 6 deletions ZLocation/ZLocation.Search.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ Set-StrictMode -Version Latest

if ((Get-Variable IsWindows -ErrorAction Ignore) -eq $null) { $IsWindows = $true }

function Find-Matches([hashtable]$hash, [string[]]$query)
{
function Find-Matches {
param (
[Parameter(Mandatory=$true)] [hashtable]$hash,
[string[]]$query
)
$hash = $hash.Clone()
foreach ($key in ($hash.GetEnumerator() | %{$_.Name}))
{
Expand Down Expand Up @@ -39,18 +42,29 @@ function Find-Matches([hashtable]$hash, [string[]]$query)
}
}

function Start-WithPrefix([string]$Path, [string]$lowerPrefix) {
function Start-WithPrefix {
param (
[Parameter(Mandatory=$true)] [string]$Path,
[Parameter(Mandatory=$true)] [string]$lowerPrefix
)
$lowerLeaf = (Split-Path -Leaf $Path).ToLower()
return $lowerLeaf.StartsWith($lowerPrefix)
}

function IsExactMatch([string]$Path, [string]$lowerPrefix) {
function IsExactMatch {
param (
[Parameter(Mandatory=$true)] [string]$Path,
[Parameter(Mandatory=$true)] [string]$lowerPrefix
)
$lowerLeaf = (Split-Path -Leaf $Path).ToLower()
return $lowerLeaf -eq $lowerPrefix
}

function Test-FuzzyMatch([string]$path, [string[]]$query)
{
function Test-FuzzyMatch {
param (
[Parameter(Mandatory=$true)] [string]$path,
[string[]]$query
)
function contains([string]$left, [string]$right) {
return [bool]($left.IndexOf($right, [System.StringComparison]::OrdinalIgnoreCase) -ge 0)
}
Expand Down
41 changes: 33 additions & 8 deletions ZLocation/ZLocation.Service.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,27 @@ class Service {
[Collections.Generic.IEnumerable[Location]] Get() {
return (dboperation {
# Return an enumerator of all location entries
[Location[]]$arr = DBFind $collection ([LiteDB.Query]::All()) ([Location])
,$arr
try {
[Location[]]$arr = DBFind $collection ([LiteDB.Query]::All()) ([Location])
, $arr
}
catch [System.InvalidCastException] {
Write-Warning "Caught InvalidCastException when reading db, probably [LiteDB.ObjectId] entry present."
$oidquery = [LiteDB.Query]::Where('_id', {$args -like '{"$oid":"*"}'})
$problementries = (,$collection.Find($oidquery))
if ($problementries.Count -gt 0) {
Write-Warning "Found $($problementries.Count) problem entries, attempting to remove..."
$problementries | Write-Debug
try {
DBDelete $collection $oidquery | Out-Null
Write-Warning 'Problem entries successfully removed, please repeat your command.'
} catch {
Write-Error 'Problem entries could not be removed.'
}
} else {
Write-Error 'No problem entries found, please open an issue on https://github.com/vors/ZLocation'
}
}
})
}
[void] Add([string]$path, [double]$weight) {
Expand Down Expand Up @@ -57,7 +76,10 @@ function Get-ZLocationLegacyBackupFilePath
See: https://github.com/mbdavid/LiteDB/wiki/Concurrency
Exposes $db and $collection variables for use by the $scriptblock
#>
function dboperation($private:scriptblock) {
function dboperation {
param (
[Parameter(Mandatory=$true)] $private:scriptblock
)
$Private:Mode = if (Get-Variable IsMacOS -ErrorAction Ignore) { 'Exclusive' } else { 'Shared' }
# $db and $collection will be in-scope within $scriptblock
$db = DBOpen "Filename=$( Get-ZLocationDatabaseFilePath ); Mode=$Mode"
Expand All @@ -68,13 +90,16 @@ function dboperation($private:scriptblock) {
try {
& $private:scriptblock
return
} catch {
$rand = Get-Random 100
Start-Sleep -Milliseconds (($__i + 1) * 100 - $rand)
} catch [System.IO.IOException] {
# The process cannot access the file '~\z-location.db' because it is being used by another process.
if ($__i -lt 4 ) {
$rand = Get-Random 100
Start-Sleep -Milliseconds (($__i + 1) * 100 - $rand)
} else {
throw [System.IO.IOException] 'Cannot execute database operation after 5 attempts, please open an issue on https://github.com/vors/ZLocation'
}
}
}
Write-Error $error[0]
throw 'Cannot execute database operation after 5 attempts, please open an issue on https://github.com/vors/ZLocation'
} finally {
$db.dispose()
}
Expand Down
11 changes: 9 additions & 2 deletions ZLocation/ZLocation.Storage.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ function Get-ZLocation($Match)
return $hash
}

function Add-ZWeight([string]$path, [double]$weight) {
function Add-ZWeight {
param (
[Parameter(Mandatory=$true)] [string]$Path,
[Parameter(Mandatory=$true)] [double]$Weight
)
$service = Get-ZService
$service.Add($path, $weight)
}

function Remove-ZLocation([string]$path) {
function Remove-ZLocation {
param (
[Parameter(Mandatory=$true)] [string]$Path
)
$service = Get-ZService
$service.Remove($path)
}
Expand Down
5 changes: 4 additions & 1 deletion ZLocation/ZLocation.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ function Update-ZLocation([string]$path)
(Get-Variable pwd).attributes.Add((new-object ValidateScript { Update-ZLocation $_.Path; return $true }))
#>

function Update-ZLocation([string]$path)
function Update-ZLocation
{
param (
[Parameter(Mandatory=$true)] [string]$Path
)
Add-ZWeight $path 1.0
}

Expand Down

0 comments on commit f6b093c

Please sign in to comment.