| | |
| | | #include <boost/uuid/random_generator.hpp> |
| | | #include <boost/uuid/string_generator.hpp> |
| | | #include <boost/uuid/uuid.hpp> |
| | | #include <sys/file.h> |
| | | |
| | | namespace |
| | | { |
| | |
| | | static_assert(AllocSizeIndex[255] > uint32_t(-1), "Make sure alloc size correct."); |
| | | |
| | | const int64_t kCenterInfoFixedAddress = 1024 * 4; |
| | | const int64_t kShmMetaInfoFixedAddress = 1024 * 16; |
| | | |
| | | const boost::uuids::uuid kCenterInfoTag = boost::uuids::string_generator()("fc5007bd-0e62-4d91-95dc-948cf1f02e5a"); |
| | | const boost::uuids::uuid kMetaInfoTag = boost::uuids::string_generator()("fc5007bd-0e62-4d91-95dc-948cf1f02e5a"); |
| | | |
| | | struct BHomeMetaInfo { |
| | | boost::uuids::uuid tag_; |
| | | std::atomic<uint64_t> shm_id_; |
| | | std::atomic<uint64_t> ssn_id_; |
| | | }; |
| | | |
| | | struct CenterMetaInfo { |
| | | boost::uuids::uuid tag_; |
| | | CenterInfo info_; |
| | |
| | | template <class T = void> |
| | | T *Ptr(const int64_t offset) { return reinterpret_cast<T *>(offset); } |
| | | |
| | | class FileLock |
| | | { |
| | | public: |
| | | FileLock(const std::string &path) : |
| | | fd_(Open(path)) |
| | | { |
| | | if (fd_ == -1) { throw std::runtime_error("error open file:" + path); } |
| | | } |
| | | ~FileLock() { Close(fd_); } |
| | | bool try_lock() { return fd_ != -1 && (flock(fd_, LOCK_EX | LOCK_NB) == 0); } |
| | | void unlock() { flock(fd_, LOCK_UN); } |
| | | |
| | | private: |
| | | static int Open(const std::string &path) { return open(path.c_str(), O_RDONLY, 0666); } |
| | | static int Close(int fd) { return close(fd); } |
| | | int fd_; |
| | | std::mutex mtx_; |
| | | }; |
| | | |
| | | SharedMemory &BHomeMetaShm() |
| | | { |
| | | static std::string name("bhshmq_meta_v0"); |
| | | static SharedMemory shm(name, 1024 * 128); |
| | | return shm; |
| | | } |
| | | |
| | | } // namespace |
| | | |
| | | CenterInfo *GetCenterInfo(SharedMemory &shm) |
| | | { |
| | | auto pmeta = Ptr<CenterMetaInfo>(kCenterInfoFixedAddress + Addr(shm.get_address())); |
| | | if (pmeta->tag_ == kCenterInfoTag) { |
| | | if (pmeta->tag_ == kMetaInfoTag) { |
| | | return &pmeta->info_; |
| | | } |
| | | return nullptr; |
| | | } |
| | | |
| | | ShmSocket &DefaultSender(SharedMemory &shm) |
| | | { |
| | | typedef std::pair<void *, std::shared_ptr<ShmSocket>> Pair; |
| | |
| | | local_cache = store.back(); |
| | | return *local_cache.second; |
| | | } |
| | | |
| | | BHomeMetaInfo *GetBHomeMeta() |
| | | { |
| | | auto p = Ptr<BHomeMetaInfo>(kShmMetaInfoFixedAddress + Addr(BHomeMetaShm().get_address())); |
| | | return (p->tag_ == kMetaInfoTag) ? p : nullptr; |
| | | } |
| | | |
| | | bool ShmMetaInit() |
| | | { |
| | | SharedMemory &shm = BHomeMetaShm(); |
| | | |
| | | static FileLock fl("/dev/shm/" + shm.name()); |
| | | if (!fl.try_lock()) { // single center instance only. |
| | | return false; |
| | | } |
| | | |
| | | auto pmeta = GetBHomeMeta(); |
| | | if (pmeta && pmeta->tag_ == kMetaInfoTag) { |
| | | ++pmeta->shm_id_; // inc shm id |
| | | return true; // already exist. |
| | | } else { |
| | | Mutex *mutex = shm.FindOrCreate<Mutex>("bhshmq_meta_lock"); |
| | | if (!mutex || !mutex->try_lock()) { |
| | | return false; |
| | | } |
| | | DEFER1(mutex->unlock()); |
| | | |
| | | auto base = Addr(shm.get_address()); |
| | | auto offset = kShmMetaInfoFixedAddress; |
| | | void *p = shm.Alloc(offset * 2); |
| | | if (Addr(p) - base <= offset) { |
| | | pmeta = new (Ptr(offset + base)) BHomeMetaInfo; |
| | | pmeta->tag_ = kMetaInfoTag; |
| | | pmeta->shm_id_ = 100; |
| | | pmeta->ssn_id_ = 10000; |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // put center info at fixed memory position. |
| | | // as boost shm find object (find socket/mq by id, etc...) also locks inside, |
| | | // which node might crash inside and cause deadlock. |
| | | bool CenterInit(SharedMemory &shm) |
| | | bool CenterInit() |
| | | { |
| | | if (!ShmMetaInit()) { return false; } |
| | | |
| | | SharedMemory &shm = BHomeShm(); |
| | | Mutex *mutex = shm.FindOrCreate<Mutex>("shm_center_lock"); |
| | | if (!mutex || !mutex->try_lock()) { |
| | | return false; |
| | |
| | | DEFER1(mutex->unlock()); |
| | | |
| | | auto pmeta = Ptr<CenterMetaInfo>(kCenterInfoFixedAddress + Addr(shm.get_address())); |
| | | if (pmeta->tag_ == kCenterInfoTag) { |
| | | if (pmeta->tag_ == kMetaInfoTag) { |
| | | return true; |
| | | } else { |
| | | auto base = Addr(shm.get_address()); |
| | |
| | | InitMQ(info.mq_center_, NextId()); |
| | | InitMQ(info.mq_bus_, NextId()); |
| | | |
| | | pmeta->tag_ = kCenterInfoTag; |
| | | pmeta->tag_ = kMetaInfoTag; |
| | | return true; |
| | | } |
| | | } |
| | |
| | | |
| | | std::string BHomeShmName() |
| | | { |
| | | return "bhome_default_shm_v0"; |
| | | auto bhome_meta = Ptr<BHomeMetaInfo>(kShmMetaInfoFixedAddress + Addr(BHomeMetaShm().get_address())); |
| | | return "bhome_shmq_id_" + std::to_string(bhome_meta->shm_id_.load()); |
| | | } |
| | | |
| | | SharedMemory &BHomeShm() |
| | | { |
| | | static SharedMemory shm(BHomeShmName(), 1024 * 1024 * 512); |
| | |
| | | |
| | | bool GlobalInit(SharedMemory &shm) { return GetCenterInfo(shm); } |
| | | |
| | | MQId NewSession() { return 10 * (++GetCenterInfo(BHomeShm())->mqid_); } |
| | | MQId NewSession() { return 10 * (++GetBHomeMeta()->ssn_id_); } |
| | | |
| | | void SetLastError(const int ec, const std::string &msg) |
| | | { |