Looking at the patch I didn't like that duplicated the page scan in a
second function without refactoring out the first scan. I think this
comes from the usual noncommiter-itus of trying to modify the existing
code as little as possible. At least that's the problem I've had which
led to things like this. Instead try to figure how you would have
written it if you were writing it from scratch.
If it's convenient to have a function to handle the scan then use it
for both scans. You could have a flag that indicates it should abort
after the first freeze. I think it would be simpler to have a return
value indicating the oldest transaction found and then just call it
again if that's old enough for the opportunistic threshold.