Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
internal-queue.h
Go to the documentation of this file.
1 // Copyright 2013 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 
16 #ifndef IMPALA_UTIL_INTERNAL_QUEUE_H
17 #define IMPALA_UTIL_INTERNAL_QUEUE_H
18 
19 #include <boost/thread/locks.hpp>
20 
21 #include "common/atomic.h"
22 #include "util/spinlock.h"
23 
24 
25 namespace impala {
26 
37 
39 template<typename T>
41  public:
42  struct Node {
43  public:
44  Node() : parent_queue(NULL), next(NULL), prev(NULL) {}
45  virtual ~Node() {}
46 
48  T* Next() const {
49  boost::lock_guard<SpinLock> lock(parent_queue->lock_);
50  return reinterpret_cast<T*>(next);
51  }
52  T* Prev() const {
53  boost::lock_guard<SpinLock> lock(parent_queue->lock_);
54  return reinterpret_cast<T*>(prev);
55  }
56 
57  private:
58  friend class InternalQueue;
59 
64  };
65 
66  InternalQueue() : head_(NULL), tail_(NULL), size_(0) {}
67 
70  T* head() const {
71  boost::lock_guard<SpinLock> lock(lock_);
72  if (empty()) return NULL;
73  return reinterpret_cast<T*>(head_);
74  }
75 
78  T* tail() {
79  boost::lock_guard<SpinLock> lock(lock_);
80  if (empty()) return NULL;
81  return reinterpret_cast<T*>(tail_);
82  }
83 
85  void Enqueue(T* n) {
86  Node* node = (Node*)n;
87  DCHECK(node->next == NULL);
88  DCHECK(node->prev == NULL);
89  DCHECK(node->parent_queue == NULL);
90  node->parent_queue = this;
91  {
92  boost::lock_guard<SpinLock> lock(lock_);
93  if (tail_ != NULL) tail_->next = node;
94  node->prev = tail_;
95  tail_ = node;
96  if (head_ == NULL) head_ = node;
97  ++size_;
98  }
99  }
100 
103  T* Dequeue() {
104  Node* result = NULL;
105  {
106  boost::lock_guard<SpinLock> lock(lock_);
107  if (empty()) return NULL;
108  --size_;
109  result = head_;
110  head_ = head_->next;
111  if (head_ == NULL) {
112  tail_ = NULL;
113  } else {
114  head_->prev = NULL;
115  }
116  }
117  DCHECK(result != NULL);
118  result->next = result->prev = NULL;
119  result->parent_queue = NULL;
120  return reinterpret_cast<T*>(result);
121  }
122 
125  T* PopBack() {
126  Node* result = NULL;
127  {
128  boost::lock_guard<SpinLock> lock(lock_);
129  if (empty()) return NULL;
130  --size_;
131  result = tail_;
132  tail_ = tail_->prev;
133  if (tail_ == NULL) {
134  head_ = NULL;
135  } else {
136  tail_->next = NULL;
137  }
138  }
139  DCHECK(result != NULL);
140  result->next = result->prev = NULL;
141  result->parent_queue = NULL;
142  return reinterpret_cast<T*>(result);
143  }
144 
147  void Remove(T* n) {
148  Node* node = (Node*)n;
149  if (node->parent_queue == NULL) return;
150  DCHECK(node->parent_queue == this);
151  {
152  boost::lock_guard<SpinLock> lock(lock_);
153  if (node->next == NULL && node->prev == NULL) {
154  // Removing only node
155  DCHECK(node == head_);
156  DCHECK(tail_ == node);
157  head_ = tail_ = NULL;
158  --size_;
159  node->parent_queue = NULL;
160  return;
161  }
162 
163  if (head_ == node) {
164  DCHECK(node->prev == NULL);
165  head_ = node->next;
166  } else {
167  DCHECK(node->prev != NULL);
168  node->prev->next = node->next;
169  }
170 
171  if (node == tail_) {
172  DCHECK(node->next == NULL);
173  tail_ = node->prev;
174  } else if (node->next != NULL) {
175  node->next->prev = node->prev;
176  }
177  --size_;
178  }
179  node->next = node->prev = NULL;
180  node->parent_queue = NULL;
181  }
182 
184  void Clear() {
185  boost::lock_guard<SpinLock> lock(lock_);
186  Node* cur = head_;
187  while (cur != NULL) {
188  Node* tmp = cur;
189  cur = cur->next;
190  tmp->prev = tmp->next = NULL;
191  tmp->parent_queue = NULL;
192  }
193  size_ = 0;
194  head_ = tail_ = NULL;
195  }
196 
197  int size() const { return size_; }
198  bool empty() const { return head_ == NULL; }
199 
202  bool Contains(const T* target) const {
203  return target->parent_queue == this;
204  }
205 
207  bool Validate() {
208  int num_elements_found = 0;
209  boost::lock_guard<SpinLock> lock(lock_);
210  if (head_ == NULL) {
211  if (tail_ != NULL) return false;
212  if (size() != 0) return false;
213  return true;
214  }
215 
216  if (head_->prev != NULL) return false;
217  Node* current = head_;
218  while (current != NULL) {
219  if (current->parent_queue != this) return false;
220  ++num_elements_found;
221  Node* next = current->next;
222  if (next == NULL) {
223  if (current != tail_) return false;
224  } else {
225  if (next->prev != current) return false;
226  }
227  current = next;
228  }
229  if (num_elements_found != size()) return false;
230  return true;
231  }
232 
234  std::string DebugString() {
235  std::stringstream ss;
236  ss << "(";
237  {
238  boost::lock_guard<SpinLock> lock(lock_);
239  Node* curr = head_;
240  while (curr != NULL) {
241  ss << (void*)curr;
242  curr = curr->next;
243  }
244  }
245  ss << ")";
246  return ss.str();
247  }
248 
249  private:
250  friend struct Node;
251  mutable SpinLock lock_;
253  int size_;
254 };
255 
256 }
257 
258 #endif
Lightweight spinlock.
Definition: spinlock.h:24
bool Contains(const T *target) const
void Enqueue(T *n)
Enqueue node onto the queue's tail. This is O(1).
void Clear()
Clears all elements in the list.
std::string DebugString()
Prints the queue ptrs to a string.
InternalQueue * parent_queue
Pointer to the queue this Node is on. NULL if not on any queue.
T must be a subclass of InternalQueue::Node.
T * Next() const
Returns the Next/Prev node or NULL if this is the end/front.
bool Validate()
Validates the internal structure of the list.