|
78 | 78 | // is retained. |
79 | 79 | historicalChannelBucket = []byte("historical-chan-bucket") |
80 | 80 |
|
| 81 | + // pendingCleanupBucket stores information about channels that have been |
| 82 | + // closed but whose data (revocation logs, forwarding packages) has not |
| 83 | + // yet been deleted. This is used by SQL backends to defer heavy cleanup |
| 84 | + // operations to startup. |
| 85 | + pendingCleanupBucket = []byte("pending-cleanup-bucket") |
| 86 | + |
81 | 87 | // chanInfoKey can be accessed within the bucket for a channel |
82 | 88 | // (identified by its chanPoint). This key stores all the static |
83 | 89 | // information for a channel which is decided at the end of the |
@@ -3759,6 +3765,57 @@ const ( |
3759 | 3765 | Abandoned ClosureType = 5 |
3760 | 3766 | ) |
3761 | 3767 |
|
| 3768 | +// PendingCleanupInfo contains the information needed to clean up a channel's |
| 3769 | +// data after it has been closed. This is used by SQL backends to defer heavy |
| 3770 | +// deletion operations to startup. |
| 3771 | +type PendingCleanupInfo struct { |
| 3772 | + // ChanPoint is the funding outpoint of the channel. |
| 3773 | + ChanPoint wire.OutPoint |
| 3774 | + |
| 3775 | + // ShortChanID is the short channel ID of the channel. |
| 3776 | + ShortChanID lnwire.ShortChannelID |
| 3777 | + |
| 3778 | + // NodePub is the compressed public key of the remote node. |
| 3779 | + NodePub [33]byte |
| 3780 | + |
| 3781 | + // ChainHash is the hash of the chain this channel belongs to. |
| 3782 | + ChainHash chainhash.Hash |
| 3783 | +} |
| 3784 | + |
| 3785 | +// Encode serializes the PendingCleanupInfo to the given writer. |
| 3786 | +func (p *PendingCleanupInfo) Encode(w io.Writer) error { |
| 3787 | + if err := WriteElements(w, p.ChanPoint, p.ShortChanID); err != nil { |
| 3788 | + return err |
| 3789 | + } |
| 3790 | + |
| 3791 | + if _, err := w.Write(p.NodePub[:]); err != nil { |
| 3792 | + return err |
| 3793 | + } |
| 3794 | + |
| 3795 | + if _, err := w.Write(p.ChainHash[:]); err != nil { |
| 3796 | + return err |
| 3797 | + } |
| 3798 | + |
| 3799 | + return nil |
| 3800 | +} |
| 3801 | + |
| 3802 | +// Decode deserializes the PendingCleanupInfo from the given reader. |
| 3803 | +func (p *PendingCleanupInfo) Decode(r io.Reader) error { |
| 3804 | + if err := ReadElements(r, &p.ChanPoint, &p.ShortChanID); err != nil { |
| 3805 | + return err |
| 3806 | + } |
| 3807 | + |
| 3808 | + if _, err := io.ReadFull(r, p.NodePub[:]); err != nil { |
| 3809 | + return err |
| 3810 | + } |
| 3811 | + |
| 3812 | + if _, err := io.ReadFull(r, p.ChainHash[:]); err != nil { |
| 3813 | + return err |
| 3814 | + } |
| 3815 | + |
| 3816 | + return nil |
| 3817 | +} |
| 3818 | + |
3762 | 3819 | // ChannelCloseSummary contains the final state of a channel at the point it |
3763 | 3820 | // was closed. Once a channel is closed, all the information pertaining to that |
3764 | 3821 | // channel within the openChannelBucket is deleted, and a compact summary is |
@@ -3853,6 +3910,10 @@ func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary, |
3853 | 3910 | c.Lock() |
3854 | 3911 | defer c.Unlock() |
3855 | 3912 |
|
| 3913 | + // Check if the backend prefers deferring heavy operations to startup. |
| 3914 | + // Postgres backends return true here to avoid lock contention. |
| 3915 | + deferCleanup := kvdb.ShouldDeferHeavyOperations(c.Db.backend) |
| 3916 | + |
3856 | 3917 | return kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error { |
3857 | 3918 | openChanBucket := tx.ReadWriteBucket(openChannelBucket) |
3858 | 3919 | if openChanBucket == nil { |
@@ -3893,37 +3954,25 @@ func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary, |
3893 | 3954 | return err |
3894 | 3955 | } |
3895 | 3956 |
|
3896 | | - // Delete all the forwarding packages stored for this particular |
3897 | | - // channel. |
3898 | | - if err = chanState.Packager.Wipe(tx); err != nil { |
3899 | | - return err |
3900 | | - } |
3901 | | - |
3902 | | - // Now that the index to this channel has been deleted, purge |
3903 | | - // the remaining channel metadata from the database. |
3904 | | - err = deleteOpenChannel(chanBucket) |
3905 | | - if err != nil { |
3906 | | - return err |
3907 | | - } |
3908 | | - |
3909 | | - // We'll also remove the channel from the frozen channel bucket |
3910 | | - // if we need to. |
3911 | | - if c.ChanType.IsFrozen() || c.ChanType.HasLeaseExpiration() { |
3912 | | - err := deleteThawHeight(chanBucket) |
| 3957 | + if deferCleanup { |
| 3958 | + // For postgres backends, store cleanup info and defer |
| 3959 | + // the heavy deletion operations to startup. |
| 3960 | + err = storePendingCleanup( |
| 3961 | + tx, c, nodePub, chanKey, |
| 3962 | + ) |
| 3963 | + if err != nil { |
| 3964 | + return err |
| 3965 | + } |
| 3966 | + } else { |
| 3967 | + // For non-postgres backends (bbolt, sqlite), perform |
| 3968 | + // immediate cleanup. |
| 3969 | + err = performImmediateCleanup( |
| 3970 | + tx, chanState, chanBucket, chainBucket, |
| 3971 | + chanPointBuf.Bytes(), |
| 3972 | + ) |
3913 | 3973 | if err != nil { |
3914 | 3974 | return err |
3915 | 3975 | } |
3916 | | - } |
3917 | | - |
3918 | | - // With the base channel data deleted, attempt to delete the |
3919 | | - // information stored within the revocation log. |
3920 | | - if err := deleteLogBucket(chanBucket); err != nil { |
3921 | | - return err |
3922 | | - } |
3923 | | - |
3924 | | - err = chainBucket.DeleteNestedBucket(chanPointBuf.Bytes()) |
3925 | | - if err != nil { |
3926 | | - return err |
3927 | 3976 | } |
3928 | 3977 |
|
3929 | 3978 | // Fetch the outpoint bucket to see if the outpoint exists or |
@@ -4733,6 +4782,71 @@ func deleteOpenChannel(chanBucket kvdb.RwBucket) error { |
4733 | 4782 | return nil |
4734 | 4783 | } |
4735 | 4784 |
|
| 4785 | +// storePendingCleanup stores cleanup info for a channel to be processed at |
| 4786 | +// startup. This is used by postgres backends to defer heavy deletion |
| 4787 | +// operations. |
| 4788 | +func storePendingCleanup(tx kvdb.RwTx, c *OpenChannel, nodePub []byte, |
| 4789 | + chanKey []byte) error { |
| 4790 | + |
| 4791 | + cleanupBucket, err := tx.CreateTopLevelBucket(pendingCleanupBucket) |
| 4792 | + if err != nil { |
| 4793 | + return err |
| 4794 | + } |
| 4795 | + |
| 4796 | + var nodePubKey [33]byte |
| 4797 | + copy(nodePubKey[:], nodePub) |
| 4798 | + |
| 4799 | + cleanupInfo := &PendingCleanupInfo{ |
| 4800 | + ChanPoint: c.FundingOutpoint, |
| 4801 | + ShortChanID: c.ShortChannelID, |
| 4802 | + NodePub: nodePubKey, |
| 4803 | + ChainHash: c.ChainHash, |
| 4804 | + } |
| 4805 | + |
| 4806 | + var cleanupBuf bytes.Buffer |
| 4807 | + if err := cleanupInfo.Encode(&cleanupBuf); err != nil { |
| 4808 | + return err |
| 4809 | + } |
| 4810 | + |
| 4811 | + return cleanupBucket.Put(chanKey, cleanupBuf.Bytes()) |
| 4812 | +} |
| 4813 | + |
| 4814 | +// performImmediateCleanup handles the cleanup operations that are performed |
| 4815 | +// immediately during channel close for non-postgres backends (bbolt, sqlite). |
| 4816 | +// This includes wiping forwarding packages, deleting channel data, thaw height, |
| 4817 | +// revocation logs, and the channel bucket itself. |
| 4818 | +func performImmediateCleanup(tx kvdb.RwTx, chanState *OpenChannel, |
| 4819 | + chanBucket kvdb.RwBucket, chainBucket kvdb.RwBucket, |
| 4820 | + chanKey []byte) error { |
| 4821 | + |
| 4822 | + // Delete all the forwarding packages stored for this channel. |
| 4823 | + if err := chanState.Packager.Wipe(tx); err != nil { |
| 4824 | + return err |
| 4825 | + } |
| 4826 | + |
| 4827 | + // Purge the remaining channel metadata from the database. |
| 4828 | + if err := deleteOpenChannel(chanBucket); err != nil { |
| 4829 | + return err |
| 4830 | + } |
| 4831 | + |
| 4832 | + // Remove the channel from the frozen channel bucket if needed. |
| 4833 | + if chanState.ChanType.IsFrozen() || |
| 4834 | + chanState.ChanType.HasLeaseExpiration() { |
| 4835 | + |
| 4836 | + if err := deleteThawHeight(chanBucket); err != nil { |
| 4837 | + return err |
| 4838 | + } |
| 4839 | + } |
| 4840 | + |
| 4841 | + // Delete the information stored within the revocation log. |
| 4842 | + if err := deleteLogBucket(chanBucket); err != nil { |
| 4843 | + return err |
| 4844 | + } |
| 4845 | + |
| 4846 | + // Delete the channel bucket itself. |
| 4847 | + return chainBucket.DeleteNestedBucket(chanKey) |
| 4848 | +} |
| 4849 | + |
4736 | 4850 | // makeLogKey converts a uint64 into an 8 byte array. |
4737 | 4851 | func makeLogKey(updateNum uint64) [8]byte { |
4738 | 4852 | var key [8]byte |
|
0 commit comments