Use a COW approach for tasks modified for Properties

Previously a task was modified directly during property expansion. This
made it unsafe to cache tasks output by the preloader and also made it
impossible to update a Node for changes after the first one. Fix this by
copying a task before expanding its properties. Only copy tasks which
actually have properties to be expanded in order to avoid the
performance hit on every task as the copying itself is expensive. Using
a COW approach is much safer and also enables many more optimizations
based on detecting whether a task was altered while eventually
refreshing nodes for each change in a query.

The performance impact of this change seems to be at the noise level.

Change-Id: Idf101dab7990683749c39d82251ece67f127eb9c
3 files changed