1
1
use crate :: {
2
+ asyncjob:: { AsyncJob , AsyncSingleJob , RunParams } ,
2
3
error:: Result ,
3
4
hash,
4
5
sync:: { self , RepoPath } ,
5
6
AsyncGitNotification ,
6
7
} ;
7
8
use crossbeam_channel:: Sender ;
8
9
use std:: {
9
- sync:: {
10
- atomic:: { AtomicUsize , Ordering } ,
11
- Arc , Mutex ,
12
- } ,
10
+ sync:: { Arc , Mutex } ,
13
11
time:: { Duration , Instant } ,
14
12
} ;
15
13
use sync:: Tags ;
16
14
17
15
///
18
16
#[ derive( Default , Clone ) ]
19
- struct TagsResult {
17
+ pub struct TagsResult {
20
18
hash : u64 ,
21
19
tags : Tags ,
22
20
}
23
21
24
22
///
25
23
pub struct AsyncTags {
26
- last : Arc < Mutex < Option < ( Instant , TagsResult ) > > > ,
24
+ last : Option < ( Instant , TagsResult ) > ,
27
25
sender : Sender < AsyncGitNotification > ,
28
- pending : Arc < AtomicUsize > ,
26
+ job : AsyncSingleJob < AsyncTagsJob > ,
29
27
repo : RepoPath ,
30
28
}
31
29
@@ -37,30 +35,27 @@ impl AsyncTags {
37
35
) -> Self {
38
36
Self {
39
37
repo,
40
- last : Arc :: new ( Mutex :: new ( None ) ) ,
38
+ last : None ,
41
39
sender : sender. clone ( ) ,
42
- pending : Arc :: new ( AtomicUsize :: new ( 0 ) ) ,
40
+ job : AsyncSingleJob :: new ( sender . clone ( ) ) ,
43
41
}
44
42
}
45
43
46
44
/// last fetched result
47
- pub fn last ( & mut self ) -> Result < Option < Tags > > {
48
- let last = self . last . lock ( ) ?;
49
-
50
- Ok ( last. clone ( ) . map ( |last| last. 1 . tags ) )
45
+ pub fn last ( & self ) -> Result < Option < Tags > > {
46
+ Ok ( self . last . as_ref ( ) . map ( |result| result. 1 . tags . clone ( ) ) )
51
47
}
52
48
53
49
///
54
50
pub fn is_pending ( & self ) -> bool {
55
- self . pending . load ( Ordering :: Relaxed ) > 0
51
+ self . job . is_pending ( )
56
52
}
57
53
58
- fn is_outdated ( & self , dur : Duration ) -> Result < bool > {
59
- let last = self . last . lock ( ) ?;
60
-
61
- Ok ( last
54
+ ///
55
+ fn is_outdated ( & self , dur : Duration ) -> bool {
56
+ self . last
62
57
. as_ref ( )
63
- . map_or ( true , |( last_time, _) | last_time. elapsed ( ) > dur) )
58
+ . map_or ( true , |( last_time, _) | last_time. elapsed ( ) > dur)
64
59
}
65
60
66
61
///
@@ -71,72 +66,106 @@ impl AsyncTags {
71
66
) -> Result < ( ) > {
72
67
log:: trace!( "request" ) ;
73
68
74
- if !force && self . is_pending ( ) {
69
+ if !force && self . job . is_pending ( ) {
75
70
return Ok ( ( ) ) ;
76
71
}
77
72
78
- let outdated = self . is_outdated ( dur) ? ;
73
+ let outdated = self . is_outdated ( dur) ;
79
74
80
75
if !force && !outdated {
81
76
return Ok ( ( ) ) ;
82
77
}
83
78
84
- let arc_last = Arc :: clone ( & self . last ) ;
85
- let sender = self . sender . clone ( ) ;
86
- let arc_pending = Arc :: clone ( & self . pending ) ;
87
-
88
- self . pending . fetch_add ( 1 , Ordering :: Relaxed ) ;
89
79
let repo = self . repo . clone ( ) ;
90
80
91
- rayon_core:: spawn ( move || {
92
- let notify = Self :: getter ( & repo, & arc_last, outdated)
93
- . expect ( "error getting tags" ) ;
94
-
95
- arc_pending. fetch_sub ( 1 , Ordering :: Relaxed ) ;
96
-
97
- sender
98
- . send ( if notify {
99
- AsyncGitNotification :: Tags
100
- } else {
101
- AsyncGitNotification :: FinishUnchanged
102
- } )
103
- . expect ( "error sending notify" ) ;
104
- } ) ;
81
+ if outdated {
82
+ self . job . spawn ( AsyncTagsJob :: new (
83
+ self . last
84
+ . as_ref ( )
85
+ . map_or ( 0 , |( _, result) | result. hash ) ,
86
+ repo,
87
+ ) ) ;
88
+
89
+ if let Some ( job) = self . job . take_last ( ) {
90
+ if let Some ( Ok ( result) ) = job. result ( ) {
91
+ self . last = Some ( result) ;
92
+ }
93
+ }
94
+ } else {
95
+ self . sender
96
+ . send ( AsyncGitNotification :: FinishUnchanged ) ?;
97
+ }
105
98
106
99
Ok ( ( ) )
107
100
}
101
+ }
102
+
103
+ enum JobState {
104
+ Request ( u64 , RepoPath ) ,
105
+ Response ( Result < ( Instant , TagsResult ) > ) ,
106
+ }
108
107
109
- fn getter (
110
- repo : & RepoPath ,
111
- arc_last : & Arc < Mutex < Option < ( Instant , TagsResult ) > > > ,
112
- outdated : bool ,
113
- ) -> Result < bool > {
114
- let tags = sync:: get_tags ( repo) ?;
115
-
116
- let hash = hash ( & tags) ;
117
-
118
- if !outdated
119
- && Self :: last_hash ( arc_last)
120
- . map ( |last| last == hash)
121
- . unwrap_or_default ( )
122
- {
123
- return Ok ( false ) ;
108
+ ///
109
+ #[ derive( Clone , Default ) ]
110
+ pub struct AsyncTagsJob {
111
+ state : Arc < Mutex < Option < JobState > > > ,
112
+ }
113
+
114
+ ///
115
+ impl AsyncTagsJob {
116
+ ///
117
+ pub fn new ( last_hash : u64 , repo : RepoPath ) -> Self {
118
+ Self {
119
+ state : Arc :: new ( Mutex :: new ( Some ( JobState :: Request (
120
+ last_hash, repo,
121
+ ) ) ) ) ,
124
122
}
123
+ }
125
124
126
- {
127
- let mut last = arc_last. lock ( ) ?;
128
- let now = Instant :: now ( ) ;
129
- * last = Some ( ( now, TagsResult { hash, tags } ) ) ;
125
+ ///
126
+ pub fn result ( & self ) -> Option < Result < ( Instant , TagsResult ) > > {
127
+ if let Ok ( mut state) = self . state . lock ( ) {
128
+ if let Some ( state) = state. take ( ) {
129
+ return match state {
130
+ JobState :: Request ( _, _) => None ,
131
+ JobState :: Response ( result) => Some ( result) ,
132
+ } ;
133
+ }
130
134
}
131
135
132
- Ok ( true )
136
+ None
133
137
}
138
+ }
139
+
140
+ impl AsyncJob for AsyncTagsJob {
141
+ type Notification = AsyncGitNotification ;
142
+ type Progress = ( ) ;
143
+
144
+ fn run (
145
+ & mut self ,
146
+ _params : RunParams < Self :: Notification , Self :: Progress > ,
147
+ ) -> Result < Self :: Notification > {
148
+ let mut notification = AsyncGitNotification :: FinishUnchanged ;
149
+ if let Ok ( mut state) = self . state . lock ( ) {
150
+ * state = state. take ( ) . map ( |state| match state {
151
+ JobState :: Request ( last_hash, repo) => {
152
+ let tags = sync:: get_tags ( & repo) ;
153
+
154
+ JobState :: Response ( tags. map ( |tags| {
155
+ let hash = hash ( & tags) ;
156
+ if last_hash != hash {
157
+ notification = AsyncGitNotification :: Tags ;
158
+ }
159
+
160
+ ( Instant :: now ( ) , TagsResult { hash, tags } )
161
+ } ) )
162
+ }
163
+ JobState :: Response ( result) => {
164
+ JobState :: Response ( result)
165
+ }
166
+ } ) ;
167
+ }
134
168
135
- fn last_hash (
136
- last : & Arc < Mutex < Option < ( Instant , TagsResult ) > > > ,
137
- ) -> Option < u64 > {
138
- last. lock ( )
139
- . ok ( )
140
- . and_then ( |last| last. as_ref ( ) . map ( |( _, last) | last. hash ) )
169
+ Ok ( notification)
141
170
}
142
171
}
0 commit comments