It’s important to recognize that Vulkan is a tool. It doesn’t decide for you what you ought to do. It presents hardware capabilities and offers you the ability to define solutions that fits within those capabilities.
For any particular use case, there is a solution. But that solution will vary depending on the details in question.
Fully double-buffering an entire terrain map of voxels might be reasonable. Alternatively, you could achieve a similar effect by grouping your voxels into fixed-sized blocks and allocation storage for more blocks than you could use at any one time, thus allowing you to modify an unused block and swap that in the next time you render.
But these are appropriate for different use cases. The block-based one is very memory efficient… if the number of blocks that get changed each frame is small. If you were modeling waves with your voxels, you’d effectively need to do double-buffering, since all the blocks are changing each frame.
But also if you’re changing blocks from different thread, the block-based solution is less thread-friendly. This is because your block allocator (the code that keeps track of which blocks are in use and which are not) is a global resource. If different threads need to allocate a block, then that block allocation needs to be guarded by a mutex (note: clever programming might get around this; I haven’t investigated this significantly). And while there are good mutexes for cases of low contention, it’s still a cost that’s higher than bumping an atomic counter to get the offset for a double-buffer scenario.
Basically, only you know enough details about your problem to know how to solve it efficiently.