1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
18 #include "include/types.h"
19 #include "common/Clock.h"
20 #include "msg/msg_types.h"
21 #include "include/rados/librados.hpp"
23 #include "test/librados/test.h"
24 #include "gtest/gtest.h"
26 using namespace librados;
28 #include "cls/lock/cls_lock_client.h"
29 #include "cls/lock/cls_lock_ops.h"
31 using namespace rados::cls::lock;
33 void lock_info(IoCtx *ioctx, string& oid, string& name, map<locker_id_t, locker_info_t>& lockers,
34 ClsLockType *assert_type, string *assert_tag)
36 ClsLockType lock_type = LOCK_NONE;
39 ASSERT_EQ(0, get_lock_info(ioctx, oid, name, &lockers, &lock_type, &tag));
40 cout << "lock: " << name << std::endl;
41 cout << " lock_type: " << cls_lock_type_str(lock_type) << std::endl;
42 cout << " tag: " << tag << std::endl;
43 cout << " lockers:" << std::endl;
46 ASSERT_EQ(*assert_type, lock_type);
50 ASSERT_EQ(*assert_tag, tag);
53 map<locker_id_t, locker_info_t>::iterator liter;
54 for (liter = lockers.begin(); liter != lockers.end(); ++liter) {
55 const locker_id_t& locker = liter->first;
56 cout << " " << locker.locker << " expiration=" << liter->second.expiration
57 << " addr=" << liter->second.addr << " cookie=" << locker.cookie << std::endl;
61 void lock_info(IoCtx *ioctx, string& oid, string& name, map<locker_id_t, locker_info_t>& lockers)
63 lock_info(ioctx, oid, name, lockers, NULL, NULL);
66 TEST(ClsLock, TestMultiLocking) {
68 std::string pool_name = get_temp_pool_name();
69 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
71 cluster.ioctx_create(pool_name.c_str(), ioctx);
72 ClsLockType lock_type_shared = LOCK_SHARED;
73 ClsLockType lock_type_exclusive = LOCK_EXCLUSIVE;
78 ASSERT_EQ("", connect_cluster_pp(cluster2));
79 cluster2.ioctx_create(pool_name.c_str(), ioctx2);
83 string lock_name = "mylock";
85 ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0));
89 /* test lock object */
91 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
93 /* test exclusive lock */
94 ASSERT_EQ(-EEXIST, l.lock_exclusive(&ioctx, oid));
96 /* test idempotency */
98 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
102 /* test second client */
104 ASSERT_EQ(-EBUSY, l2.lock_exclusive(&ioctx2, oid));
105 ASSERT_EQ(-EBUSY, l2.lock_shared(&ioctx2, oid));
108 ASSERT_EQ(0, list_locks(&ioctx, oid, &locks));
110 ASSERT_EQ(1, (int)locks.size());
111 list<string>::iterator iter = locks.begin();
112 map<locker_id_t, locker_info_t> lockers;
113 lock_info(&ioctx, oid, *iter, lockers, &lock_type_exclusive, NULL);
115 ASSERT_EQ(1, (int)lockers.size());
118 ASSERT_EQ(0, l.unlock(&ioctx, oid));
120 ASSERT_EQ(0, list_locks(&ioctx, oid, &locks));
122 /* test shared lock */
123 ASSERT_EQ(0, l2.lock_shared(&ioctx2, oid));
124 ASSERT_EQ(0, l.lock_shared(&ioctx, oid));
127 ASSERT_EQ(0, list_locks(&ioctx, oid, &locks));
128 ASSERT_EQ(1, (int)locks.size());
129 iter = locks.begin();
130 lock_info(&ioctx, oid, *iter, lockers, &lock_type_shared, NULL);
131 ASSERT_EQ(2, (int)lockers.size());
133 /* test break locks */
134 entity_name_t name = entity_name_t::CLIENT(cluster.get_instance_id());
135 entity_name_t name2 = entity_name_t::CLIENT(cluster2.get_instance_id());
137 l2.break_lock(&ioctx2, oid, name);
138 lock_info(&ioctx, oid, *iter, lockers);
139 ASSERT_EQ(1, (int)lockers.size());
140 map<locker_id_t, locker_info_t>::iterator liter = lockers.begin();
141 const locker_id_t& id = liter->first;
142 ASSERT_EQ(name2, id.locker);
145 Lock l_tag(lock_name);
146 l_tag.set_tag("non-default tag");
147 ASSERT_EQ(-EBUSY, l_tag.lock_shared(&ioctx, oid));
150 /* test modify description */
151 string description = "new description";
152 l.set_description(description);
153 ASSERT_EQ(0, l.lock_shared(&ioctx, oid));
155 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
158 TEST(ClsLock, TestMeta) {
160 std::string pool_name = get_temp_pool_name();
161 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
163 cluster.ioctx_create(pool_name.c_str(), ioctx);
168 ASSERT_EQ("", connect_cluster_pp(cluster2));
169 cluster2.ioctx_create(pool_name.c_str(), ioctx2);
173 string lock_name = "mylock";
175 ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0));
178 ASSERT_EQ(0, l.lock_shared(&ioctx, oid));
181 Lock l_tag(lock_name);
182 l_tag.set_tag("non-default tag");
183 ASSERT_EQ(-EBUSY, l_tag.lock_shared(&ioctx2, oid));
186 ASSERT_EQ(0, l.unlock(&ioctx, oid));
188 /* test description */
190 string description = "new description";
191 l2.set_description(description);
192 ASSERT_EQ(0, l2.lock_shared(&ioctx2, oid));
194 map<locker_id_t, locker_info_t> lockers;
195 lock_info(&ioctx, oid, lock_name, lockers, NULL, NULL);
196 ASSERT_EQ(1, (int)lockers.size());
198 map<locker_id_t, locker_info_t>::iterator iter = lockers.begin();
199 locker_info_t locker = iter->second;
200 ASSERT_EQ("new description", locker.description);
202 ASSERT_EQ(0, l2.unlock(&ioctx2, oid));
205 string new_tag = "new_tag";
208 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
209 lock_info(&ioctx, oid, lock_name, lockers, NULL, &new_tag);
210 ASSERT_EQ(1, (int)lockers.size());
212 ASSERT_EQ(-EBUSY, l.lock_exclusive(&ioctx, oid));
214 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
216 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
219 TEST(ClsLock, TestCookie) {
221 std::string pool_name = get_temp_pool_name();
222 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
224 cluster.ioctx_create(pool_name.c_str(), ioctx);
227 string lock_name = "mylock";
230 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
233 string cookie = "new cookie";
234 l.set_cookie(cookie);
235 ASSERT_EQ(-EBUSY, l.lock_exclusive(&ioctx, oid));
236 ASSERT_EQ(-ENOENT, l.unlock(&ioctx, oid));
238 ASSERT_EQ(0, l.unlock(&ioctx, oid));
240 map<locker_id_t, locker_info_t> lockers;
241 lock_info(&ioctx, oid, lock_name, lockers);
242 ASSERT_EQ(0, (int)lockers.size());
244 l.set_cookie(cookie);
245 ASSERT_EQ(0, l.lock_shared(&ioctx, oid));
247 ASSERT_EQ(0, l.lock_shared(&ioctx, oid));
249 lock_info(&ioctx, oid, lock_name, lockers);
250 ASSERT_EQ(2, (int)lockers.size());
252 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
255 TEST(ClsLock, TestMultipleLocks) {
257 std::string pool_name = get_temp_pool_name();
258 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
260 cluster.ioctx_create(pool_name.c_str(), ioctx);
264 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
267 ASSERT_EQ(0, l2.lock_exclusive(&ioctx, oid));
270 ASSERT_EQ(0, list_locks(&ioctx, oid, &locks));
272 ASSERT_EQ(2, (int)locks.size());
274 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
277 TEST(ClsLock, TestLockDuration) {
279 std::string pool_name = get_temp_pool_name();
280 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
282 cluster.ioctx_create(pool_name.c_str(), ioctx);
288 utime_t start = ceph_clock_now();
289 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
290 int r = l.lock_exclusive(&ioctx, oid);
292 // it's possible to get success if we were just really slow...
293 ASSERT_TRUE(ceph_clock_now() > start + dur);
295 ASSERT_EQ(-EEXIST, r);
299 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
301 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
304 TEST(ClsLock, TestAssertLocked) {
306 std::string pool_name = get_temp_pool_name();
307 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
309 cluster.ioctx_create(pool_name.c_str(), ioctx);
313 ASSERT_EQ(0, l.lock_exclusive(&ioctx, oid));
315 librados::ObjectWriteOperation op1;
316 l.assert_locked_exclusive(&op1);
317 ASSERT_EQ(0, ioctx.operate(oid, &op1));
319 librados::ObjectWriteOperation op2;
320 l.assert_locked_shared(&op2);
321 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op2));
324 librados::ObjectWriteOperation op3;
325 l.assert_locked_exclusive(&op3);
326 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op3));
329 l.set_cookie("cookie");
330 librados::ObjectWriteOperation op4;
331 l.assert_locked_exclusive(&op4);
332 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op4));
335 ASSERT_EQ(0, l.unlock(&ioctx, oid));
337 librados::ObjectWriteOperation op5;
338 l.assert_locked_exclusive(&op5);
339 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op5));
341 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
344 TEST(ClsLock, TestSetCookie) {
346 std::string pool_name = get_temp_pool_name();
347 ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
349 cluster.ioctx_create(pool_name.c_str(), ioctx);
352 string name = "name";
354 string cookie = "cookie";
355 string new_cookie = "new cookie";
356 librados::ObjectWriteOperation op1;
357 set_cookie(&op1, name, LOCK_SHARED, cookie, tag, new_cookie);
358 ASSERT_EQ(-ENOENT, ioctx.operate(oid, &op1));
360 librados::ObjectWriteOperation op2;
361 lock(&op2, name, LOCK_SHARED, cookie, tag, "", utime_t{}, 0);
362 ASSERT_EQ(0, ioctx.operate(oid, &op2));
364 librados::ObjectWriteOperation op3;
365 lock(&op3, name, LOCK_SHARED, "cookie 2", tag, "", utime_t{}, 0);
366 ASSERT_EQ(0, ioctx.operate(oid, &op3));
368 librados::ObjectWriteOperation op4;
369 set_cookie(&op4, name, LOCK_SHARED, cookie, tag, cookie);
370 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op4));
372 librados::ObjectWriteOperation op5;
373 set_cookie(&op5, name, LOCK_SHARED, cookie, "wrong tag", new_cookie);
374 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op5));
376 librados::ObjectWriteOperation op6;
377 set_cookie(&op6, name, LOCK_SHARED, "wrong cookie", tag, new_cookie);
378 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op6));
380 librados::ObjectWriteOperation op7;
381 set_cookie(&op7, name, LOCK_EXCLUSIVE, cookie, tag, new_cookie);
382 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op7));
384 librados::ObjectWriteOperation op8;
385 set_cookie(&op8, name, LOCK_SHARED, cookie, tag, "cookie 2");
386 ASSERT_EQ(-EBUSY, ioctx.operate(oid, &op8));
388 librados::ObjectWriteOperation op9;
389 set_cookie(&op9, name, LOCK_SHARED, cookie, tag, new_cookie);
390 ASSERT_EQ(0, ioctx.operate(oid, &op9));
392 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));