<commit_before>/*******************************************************************************
 * c7a/data/block_queue.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Tobias Sturm <tobias.sturm@student.kit.edu>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_DATA_BLOCK_QUEUE_HEADER
#define C7A_DATA_BLOCK_QUEUE_HEADER

#include <c7a/data/block.hpp>
#include <c7a/data/block_reader.hpp>
#include <c7a/data/block_writer.hpp>
#include <c7a/common/concurrent_bounded_queue.hpp>

#include <atomic>
#include <memory>

namespace c7a {
namespace data {

template <size_t BlockSize>
class BlockQueueSource;

template <size_t BlockSize = default_block_size>
class ReadableBlockQueue
{
public:
    using Reader = BlockReader<BlockQueueSource<BlockSize> >;
    using VirtualBlock = data::VirtualBlock<BlockSize>;
    virtual VirtualBlock Pop() = 0;

    virtual bool closed() const = 0;

    virtual bool empty() const = 0;

    //! return number of block in the queue. Use this ONLY for DEBUGGING!
    virtual size_t size() = 0;

    //! Return a BlockReader fetching blocks from this BlockQueue.
    //! This call blocks until the queue has at least one block
    virtual Reader GetReader() = 0;
};

//! A BlockQueue is used to hand-over blocks between threads. It fulfills the
//same interface as \ref c7a::data::Stream and \ref c7a::data::File
template <size_t BlockSize = default_block_size>
class BlockQueue : public BlockSink<BlockSize>, public ReadableBlockQueue<BlockSize>
{
public:
    using Block = data::Block<BlockSize>;
    using BlockPtr = std::shared_ptr<Block>;

    using VirtualBlock = data::VirtualBlock<BlockSize>;

    using Writer = BlockWriterBase<BlockSize>;
    using Reader = BlockReader<BlockQueueSource<BlockSize> >;

    void Append(VirtualBlock&& vb) override {
        queue_.emplace(std::move(vb));
    }

    void Close() override {
        assert(!closed_); //racing condition tolerated
        closed_ = true;

        // enqueue a closing VirtualBlock.
        queue_.emplace(nullptr, 0, 0, 0);
    }

    VirtualBlock Pop() {
        VirtualBlock vb;
        queue_.pop(vb);
        return std::move(vb);
    }

    bool closed() const { return closed_; }

    bool empty() const { return queue_.empty(); }

    //! return number of block in the queue. Use this ONLY for DEBUGGING!
    size_t size() { return queue_.size() - (closed() ? 1 : 0); }

    //! Return a BlockWriter delivering to this BlockQueue.
    Writer GetWriter() { return Writer(this); }

    //! see \ref ReadableBlockQueue
    Reader GetReader();

private:
    common::ConcurrentBoundedQueue<VirtualBlock> queue_;
    std::atomic<bool> closed_ = { false };
};

//! An OrderedMultiBlockQueue holds multiple BlockQueues and unifies them.
//! Pop will consume queue after queue, each until it is exhausted
//! The order of the queue consumption is always ascending
//! The OrderedMultiBlockQueue is read-only / no sink
template <size_t BlockSize = default_block_size>
class OrderedMultiBlockQueue : public ReadableBlockQueue<BlockSize>
{
    using Block = data::Block<BlockSize>;
    using BlockQueue = data::BlockQueue<BlockSize>;
    using BlockPtr = std::shared_ptr<Block>;
    using VirtualBlock = data::VirtualBlock<BlockSize>;
    using Reader = BlockReader<BlockQueueSource<BlockSize> >;

public:
    OrderedMultiBlockQueue(const std::vector<std::reference_wrapper<BlockQueue> >& queues) : queues_(queues) { }

    VirtualBlock Pop() {
        VirtualBlock vblock(nullptr, 0, 0, 0);
        //proceed to queue that has elements or waits for elements (aka not closed)
        while (vblock.IsEndBlock()) {
            while (
                queues_[current_queue_].get().empty() &&
                queues_[current_queue_].get().closed() &&
                current_queue_ < queues_.size()
                ) { current_queue_++; }

            if (current_queue_ == queues_.size()) //end of all queues
                return VirtualBlock(nullptr, 0, 0, 0);
            vblock = queues_[current_queue_].get().Pop();
        }
        return vblock;
    }

    bool closed() const {
        bool closed = true;
        for (const BlockQueue& q : queues_)
            closed = closed & q.closed();
        return closed;
    }

    bool empty() const {
        bool empty = true;
        for (const BlockQueue& q : queues_)
            empty = empty & q.empty();
        return empty;
    }

    //! return number of block in the queue. Use this ONLY for DEBUGGING!
    size_t size() {
        size_t result = 0;
        for (BlockQueue& q : queues_)
            result += q.size();
        return result;
    }

    //! see \ref ReadableBlockQueue
    Reader GetReader();

private:
    std::vector<std::reference_wrapper<BlockQueue> > queues_;
    size_t current_queue_ = 0;
};

//! A BlockSource to read Blocks from a BlockQueue using a BlockReader.
template <size_t BlockSize>
class BlockQueueSource
{
public:
    using Byte = unsigned char;

    using Block = data::Block<BlockSize>;
    using BlockCPtr = std::shared_ptr<const Block>;

    using VirtualBlock = data::VirtualBlock<BlockSize>;

    //! Start reading from a BlockQueue
    explicit BlockQueueSource(ReadableBlockQueue<BlockSize>& queue)
        : queue_(queue)
    { }

    //! Initialize the first block to be read by BlockReader
    void Initialize(const Byte** out_current, const Byte** out_end) {
        if (!NextBlock(out_current, out_end))
            *out_current = *out_end = nullptr;
    }

    //! Advance to next block of file, delivers current_ and end_ for
    //! BlockReader. Returns false if the source is empty.
    bool NextBlock(const Byte** out_current, const Byte** out_end) {
        VirtualBlock vb = queue_.Pop();
        block_ = vb.block;

        if (block_) {
            *out_current = block_->begin();
            *out_end = block_->begin() + vb.bytes_used;
            return true;
        }
        else {
            // termination block received.
            return false;
        }
    }

    bool closed() const {
        return queue_.closed();
    }

protected:
    //! BlockQueue that blocks are retrieved from
    ReadableBlockQueue<BlockSize>& queue_;

    //! The current block being read.
    BlockCPtr block_;
};

template <size_t BlockSize>
typename BlockQueue<BlockSize>::Reader BlockQueue<BlockSize>::GetReader() {
    return BlockQueue<BlockSize>::Reader(BlockQueueSource<BlockSize>(*this));
}
template <size_t BlockSize>
typename OrderedMultiBlockQueue<BlockSize>::Reader OrderedMultiBlockQueue<BlockSize>::GetReader() {
    return OrderedMultiBlockQueue<BlockSize>::Reader(BlockQueueSource<BlockSize>(*this));
}
} // namespace data
} // namespace c7a

#endif // !C7A_DATA_BLOCK_QUEUE_HEADER

/******************************************************************************/
<commit_msg>Fix OrderedMultiBlockQueue<commit_after>/*******************************************************************************
 * c7a/data/block_queue.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Tobias Sturm <tobias.sturm@student.kit.edu>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_DATA_BLOCK_QUEUE_HEADER
#define C7A_DATA_BLOCK_QUEUE_HEADER

#include <c7a/data/block.hpp>
#include <c7a/data/block_reader.hpp>
#include <c7a/data/block_writer.hpp>
#include <c7a/common/concurrent_bounded_queue.hpp>

#include <atomic>
#include <memory>

namespace c7a {
namespace data {

template <size_t BlockSize>
class BlockQueueSource;

template <size_t BlockSize = default_block_size>
class ReadableBlockQueue
{
public:
    using Reader = BlockReader<BlockQueueSource<BlockSize> >;
    using VirtualBlock = data::VirtualBlock<BlockSize>;
    virtual VirtualBlock Pop() = 0;

    virtual bool closed() const = 0;

    virtual bool empty() const = 0;

    //! return number of block in the queue. Use this ONLY for DEBUGGING!
    virtual size_t size() = 0;

    //! Return a BlockReader fetching blocks from this BlockQueue.
    //! This call blocks until the queue has at least one block
    virtual Reader GetReader() = 0;
};

//! A BlockQueue is used to hand-over blocks between threads. It fulfills the
//same interface as \ref c7a::data::Stream and \ref c7a::data::File
template <size_t BlockSize = default_block_size>
class BlockQueue : public BlockSink<BlockSize>, public ReadableBlockQueue<BlockSize>
{
public:
    using Block = data::Block<BlockSize>;
    using BlockPtr = std::shared_ptr<Block>;

    using VirtualBlock = data::VirtualBlock<BlockSize>;

    using Writer = BlockWriterBase<BlockSize>;
    using Reader = BlockReader<BlockQueueSource<BlockSize> >;

    void Append(VirtualBlock&& vb) override {
        queue_.emplace(std::move(vb));
    }

    void Close() override {
        assert(!closed_); //racing condition tolerated
        closed_ = true;

        // enqueue a closing VirtualBlock.
        queue_.emplace(nullptr, 0, 0, 0);
    }

    VirtualBlock Pop() {
        VirtualBlock vb;
        queue_.pop(vb);
        return std::move(vb);
    }

    bool closed() const { return closed_; }

    bool empty() const { return queue_.empty(); }

    //! return number of block in the queue. Use this ONLY for DEBUGGING!
    size_t size() { return queue_.size() - (closed() ? 1 : 0); }

    //! Return a BlockWriter delivering to this BlockQueue.
    Writer GetWriter() { return Writer(this); }

    //! see \ref ReadableBlockQueue
    Reader GetReader();

private:
    common::ConcurrentBoundedQueue<VirtualBlock> queue_;
    std::atomic<bool> closed_ = { false };
};

//! An OrderedMultiBlockQueue holds multiple BlockQueues and unifies them.
//! Pop will consume queue after queue, each until it is exhausted
//! The order of the queue consumption is always ascending
//! The OrderedMultiBlockQueue is read-only / no sink
template <size_t BlockSize = default_block_size>
class OrderedMultiBlockQueue : public ReadableBlockQueue<BlockSize>
{
    using Block = data::Block<BlockSize>;
    using BlockQueue = data::BlockQueue<BlockSize>;
    using BlockPtr = std::shared_ptr<Block>;
    using VirtualBlock = data::VirtualBlock<BlockSize>;
    using Reader = BlockReader<BlockQueueSource<BlockSize> >;

public:
    OrderedMultiBlockQueue(const std::vector<std::reference_wrapper<BlockQueue> >& queues) : queues_(queues) { }

    VirtualBlock Pop() {
        VirtualBlock vblock(nullptr, 0, 0, 0);
        //proceed to queue that has elements or waits for elements (aka not closed)
        while (vblock.IsEndBlock()) {
            while (
                current_queue_ < queues_.size() &&
                queues_[current_queue_].get().empty() &&
                queues_[current_queue_].get().closed()
                ) { current_queue_++; }

            if (current_queue_ == queues_.size()) //end of all queues
                return VirtualBlock(nullptr, 0, 0, 0);
            vblock = queues_[current_queue_].get().Pop();
        }
        return vblock;
    }

    bool closed() const {
        bool closed = true;
        for (const BlockQueue& q : queues_)
            closed = closed & q.closed();
        return closed;
    }

    bool empty() const {
        bool empty = true;
        for (const BlockQueue& q : queues_)
            empty = empty & q.empty();
        return empty;
    }

    //! return number of block in the queue. Use this ONLY for DEBUGGING!
    size_t size() {
        size_t result = 0;
        for (BlockQueue& q : queues_)
            result += q.size();
        return result;
    }

    //! see \ref ReadableBlockQueue
    Reader GetReader();

private:
    std::vector<std::reference_wrapper<BlockQueue> > queues_;
    size_t current_queue_ = 0;
};

//! A BlockSource to read Blocks from a BlockQueue using a BlockReader.
template <size_t BlockSize>
class BlockQueueSource
{
public:
    using Byte = unsigned char;

    using Block = data::Block<BlockSize>;
    using BlockCPtr = std::shared_ptr<const Block>;

    using VirtualBlock = data::VirtualBlock<BlockSize>;

    //! Start reading from a BlockQueue
    explicit BlockQueueSource(ReadableBlockQueue<BlockSize>& queue)
        : queue_(queue)
    { }

    //! Initialize the first block to be read by BlockReader
    void Initialize(const Byte** out_current, const Byte** out_end) {
        if (!NextBlock(out_current, out_end))
            *out_current = *out_end = nullptr;
    }

    //! Advance to next block of file, delivers current_ and end_ for
    //! BlockReader. Returns false if the source is empty.
    bool NextBlock(const Byte** out_current, const Byte** out_end) {
        VirtualBlock vb = queue_.Pop();
        block_ = vb.block;

        if (block_) {
            *out_current = block_->begin();
            *out_end = block_->begin() + vb.bytes_used;
            return true;
        }
        else {
            // termination block received.
            return false;
        }
    }

    bool closed() const {
        return queue_.closed();
    }

protected:
    //! BlockQueue that blocks are retrieved from
    ReadableBlockQueue<BlockSize>& queue_;

    //! The current block being read.
    BlockCPtr block_;
};

template <size_t BlockSize>
typename BlockQueue<BlockSize>::Reader BlockQueue<BlockSize>::GetReader() {
    return BlockQueue<BlockSize>::Reader(BlockQueueSource<BlockSize>(*this));
}
template <size_t BlockSize>
typename OrderedMultiBlockQueue<BlockSize>::Reader OrderedMultiBlockQueue<BlockSize>::GetReader() {
    return OrderedMultiBlockQueue<BlockSize>::Reader(BlockQueueSource<BlockSize>(*this));
}
} // namespace data
} // namespace c7a

#endif // !C7A_DATA_BLOCK_QUEUE_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

/*
   This is some wisdom from Cygnus's web page.  If you just try to use
   the "stringify" operator on a preprocessor directive, you'd get
   "PLATFORM", not "Intel Linux" (or whatever the value of PLATFORM
   is).  That's because the stringify operator is a special case, and
   the preprocessor isn't allowed to expand things that are passed to
   it.  However, by defining two layers of macros, you get the right
   behavior, since the first pass converts:

   xstr(PLATFORM) -> str(Intel Linux)

   and the next pass gives:

   str(Intel Linux) -> "Intel Linux"

   This is exactly what we want, so we use it.  -Derek Wright and Jeff
   Ballard, 12/2/99

   Also, because the NT build system is totally different, we have to
   define the correct platform string right in here. :( -Derek 12/3/99
*/

#define xstr(s) str(s)
#define str(s) #s

#if defined(WIN32)
#define PLATFORM INTEL-WINNT50
#endif

/* Via configure, one may have specified a particular buildid string to use
	in the version string. So honor that request here. */
#if defined(BUILDID)
#define BUILDIDSTR " BuildID: " xstr(BUILDID)
#else
#define BUILDIDSTR ""
#endif

/* Here is the version string - update before a public release */
/* --- IMPORTANT!  THE FORMAT OF THE VERSION STRING IS VERY STRICT
   BECAUSE IT IS PARSED AT RUNTIME.  DO NOT ALTER THE FORMAT OR ENTER
   ANYTHING EXTRA BEFORE THE DATE.  IF YOU WISH TO ADD EXTRA INFORMATION,
   DO SO _AFTER_ THE BUILDIDSTR AND BEFORE THE TRAILING '$' CHARACTER.
   EXAMPLES:
       $CondorVersion: 6.9.5 " __DATE__ BUILDIDSTR " WinNTPreview $ [OK]
	   $CondorVersion: 6.9.5 WinNTPreview " __DATE__ BUILDIDSTR " $ [WRONG!!!]
   Any questions?  See Todd or Derek.  Note: if you mess it up, DaemonCore
   will EXCEPT at startup time.
*/

static char* CondorVersionString = "$CondorVersion: 7.1.2 " __DATE__ BUILDIDSTR " PRE-RELEASE-UWCS $";

/* Here is the platform string.  You don't need to edit this */
static char* CondorPlatformString = "$CondorPlatform: " xstr(PLATFORM) " $";

extern "C" {

const char*
CondorVersion( void )
{
	return CondorVersionString;
}

const char*
CondorPlatform( void )
{
	return CondorPlatformString;
}

} /* extern "C" */

<commit_msg>set official version string for 7.1.3<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

/*
   This is some wisdom from Cygnus's web page.  If you just try to use
   the "stringify" operator on a preprocessor directive, you'd get
   "PLATFORM", not "Intel Linux" (or whatever the value of PLATFORM
   is).  That's because the stringify operator is a special case, and
   the preprocessor isn't allowed to expand things that are passed to
   it.  However, by defining two layers of macros, you get the right
   behavior, since the first pass converts:

   xstr(PLATFORM) -> str(Intel Linux)

   and the next pass gives:

   str(Intel Linux) -> "Intel Linux"

   This is exactly what we want, so we use it.  -Derek Wright and Jeff
   Ballard, 12/2/99

   Also, because the NT build system is totally different, we have to
   define the correct platform string right in here. :( -Derek 12/3/99
*/

#define xstr(s) str(s)
#define str(s) #s

#if defined(WIN32)
#define PLATFORM INTEL-WINNT50
#endif

/* Via configure, one may have specified a particular buildid string to use
	in the version string. So honor that request here. */
#if defined(BUILDID)
#define BUILDIDSTR " BuildID: " xstr(BUILDID)
#else
#define BUILDIDSTR ""
#endif

/* Here is the version string - update before a public release */
/* --- IMPORTANT!  THE FORMAT OF THE VERSION STRING IS VERY STRICT
   BECAUSE IT IS PARSED AT RUNTIME.  DO NOT ALTER THE FORMAT OR ENTER
   ANYTHING EXTRA BEFORE THE DATE.  IF YOU WISH TO ADD EXTRA INFORMATION,
   DO SO _AFTER_ THE BUILDIDSTR AND BEFORE THE TRAILING '$' CHARACTER.
   EXAMPLES:
       $CondorVersion: 6.9.5 " __DATE__ BUILDIDSTR " WinNTPreview $ [OK]
	   $CondorVersion: 6.9.5 WinNTPreview " __DATE__ BUILDIDSTR " $ [WRONG!!!]
   Any questions?  See Todd or Derek.  Note: if you mess it up, DaemonCore
   will EXCEPT at startup time.
*/

static char* CondorVersionString = "$CondorVersion: 7.1.3 " __DATE__ BUILDIDSTR " PRE-RELEASE-UWCS $";

/* Here is the platform string.  You don't need to edit this */
static char* CondorPlatformString = "$CondorPlatform: " xstr(PLATFORM) " $";

extern "C" {

const char*
CondorVersion( void )
{
	return CondorVersionString;
}

const char*
CondorPlatform( void )
{
	return CondorPlatformString;
}

} /* extern "C" */

<|endoftext|>


<commit_before>// @(#)root/proofd:$Name:  $:$Id: XrdProofGroup.cxx,v 1.1 2007/06/12 13:51:03 ganis Exp $
// Author: Gerardo Ganis  June 2007

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// XrdProofGroup                                                        //
//                                                                      //
// Authors: G. Ganis, CERN, 2007                                        //
//                                                                      //
// Class describing groups                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////
#include "XrdProofdPlatform.h"

#include "XrdProofGroup.h"
#include "XrdProofdTrace.h"

static const char *gTraceID = " ";
extern XrdOucTrace *XrdProofdTrace;

// Local definitions
#define TRACEID gTraceID

// Functions used in scanning hash tables

//__________________________________________________________________________
static int CheckUser(const char *, XrdProofGroup *g, void *u)
{
   // Check if user 'u' is memmebr of group 'grp'

   const char *usr = (const char *)u;

   if (g && usr && g->HasMember(usr))
      // Found the group
      return 1;

   // Check next
   return 0;
}

//__________________________________________________________________________
static int ExportGroup(const char *, XrdProofGroup *g, void *u)
{
   // Add a string describing group 'g' to a global string

   XrdOucString *msg = (XrdOucString *)u;

   if (msg->length() > 0)
      *msg += '\n';

   *msg = g->Name(); *msg += ": ";
   *msg += ", size: ";
   *msg += g->Size();
   *msg += ", members(s): ";
   *msg += g->Members();

   return 0;
}

//__________________________________________________________________________
static int PrintGroup(const char *, XrdProofGroup *g, void *)
{
   // Print info describing group 'g' to stdout

   if (g)
      g->Print();

   return 0;
}

//__________________________________________________________________________
static int AuxFunc(const char *, XrdProofGroup *g, void *s)
{
   // Generic function used for auxiliary purpose

   XrdOucString *opt = (XrdOucString *)s;

   if (!opt || opt->length() <= 0 || (*opt) == "getfirst")
      // Stop going through the table
      return 1;

   if (opt->beginswith("getnextgrp:")) {
      XrdOucString grp("||");
      grp.insert(g->Name(),1);
      if (opt->find(grp) == STR_NPOS) {
         *opt += grp;
         return 1;
      }
   }

   // Process next
   return 0;
}

//__________________________________________________________________________
XrdProofGroup::XrdProofGroup(const char *n, const char *m)
              : fName(n), fMembers(m)
{
   // Constructor

   fSize = 0;
   fActive = 0;
   fPriority = -1;
   fFraction = -1;
   fFracEff = 0;
   fMutex = new XrdOucRecMutex;
}
//__________________________________________________________________________
XrdProofGroup::~XrdProofGroup()
{
   // Destructor

   if (fMutex)
      delete fMutex;
   fMutex = 0;
}

//__________________________________________________________________________
void XrdProofGroup::Print()
{
   // Dump group content

   XrdOucMutexHelper mhp(fMutex);

   if (fName != "default") {
      XPDPRT("+++ Group: "<<fName<<", size "<<fSize<<" member(s) ("<<fMembers<<")");
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   } else {
      XPDPRT("+++ Group: "<<fName);
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   }
}

//__________________________________________________________________________
void XrdProofGroup::Count(const char *usr, int n)
{
   // Modify the active count

   // A username must be defined and an action required
   if (!usr || strlen(usr) == 0 || n == 0)
      return;

   // Reference string
   XrdOucString u(usr);
   u += ",";

   XrdOucMutexHelper mhp(fMutex);

   // If we are named, the user must be a member
   if (fName != "unnamed" && fMembers.find(u) == STR_NPOS)
      return;

   if (n > 0) {

      // Don't count it if already done
      if (fActives.find(u) != STR_NPOS)
         return;

      fActives += u;

   } else {

      // Don't remove it if not active
      if (fActives.find(u) == STR_NPOS)
         return;

      fActives.replace(u,"");
   }

   // Count
   fActive += n;
}

//__________________________________________________________________________
bool XrdProofGroup::HasMember(const char *usr)
{
   // Check if 'usr' is member of this group

   XrdOucMutexHelper mhp(fMutex);
   XrdOucString u(usr); u += ",";
   int iu = fMembers.find(u);
   if (iu != STR_NPOS)
      if (iu == 0 || u[iu-1] == ',')
         return 1;
   return 0;
}

//__________________________________________________________________________
XrdProofGroupMgr::XrdProofGroupMgr(const char *fn)
{
   // Constructor

   ResetIter();
   Config(fn);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Apply(int (*f)(const char *, XrdProofGroup *,
                                                void *), void *arg)
{
   // Apply function 'f' to the hash table of groups; 'arg' is passed to 'f'
   // in the last argument. After applying 'f', the action depends on the
   // return value with the following rule:
   //         < 0 - the hash table item is deleted.
   //         = 0 - the next hash table item is processed.
   //         > 0 - processing stops and the hash table item is returned.

   return (fGroups.Num() > 0 ? fGroups.Apply(f,arg) : (XrdProofGroup *)0);
}

//__________________________________________________________________________
XrdOucString XrdProofGroupMgr::Export(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   XrdOucString msg;

   if (!grp) {
      fGroups.Apply(ExportGroup, (void *) &msg);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      ExportGroup(grp, g, (void *) &msg);
   }

   return msg;
}

//__________________________________________________________________________
void XrdProofGroupMgr::Print(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   if (!grp) {
      fGroups.Apply(PrintGroup, 0);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      PrintGroup(grp, g, 0);
   }

   return;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetGroup(const char *grp)
{
   // Returns the instance of for group 'grp.
   // Return 0 in the case the group does not exist

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0)
      return fGroups.Find(grp);
   return (XrdProofGroup *)0;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetUserGroup(const char *usr, const char *grp)
{
   // Returns the instance of the first group to which this user belongs;
   // if grp != 0, return the instance corresponding to group 'grp', if
   // existing and the // user belongs to it.
   // Return 0 in the case the user does not belong to any group or does not
   // belong to 'grp'.

   XrdProofGroup *g = 0;

   // Check inputs
   if (!usr || strlen(usr) <= 0)
      return g;

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0) {
      g = fGroups.Find(grp);
      if (g && g->HasMember(usr))
         return g;
      else
         return (XrdProofGroup *)0;
   }

   // Scan the table
   g = fGroups.Apply(CheckUser, (void *)usr);

   // Assign to "default" group if nothing was found
   return ((!g) ? fGroups.Find("default") : g);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Next()
{
   // Returns the instance of next group in the pseudo-iterator
   // functionality. To scan over all the groups do the following:
   //         ResetIter();
   //         while ((g = Next())) {
   //            // ... Process group
   //         }
   // Return 0 when there are no more groups

   return fGroups.Apply(AuxFunc,&fIterator);
}

//__________________________________________________________________________
int XrdProofGroupMgr::Config(const char *fn)
{
   // (Ri-)configure the group info using the file 'fn'.
   // Return the number of active groups or -1 in case of error.

   if (!fn || strlen(fn) <= 0) {
      // This call is to reset existing info and remain with
      // the 'default' group only
      XrdOucMutexHelper mhp(fMutex);
      // Reset existing info
      fGroups.Purge();
      // Create "default" group
      fGroups.Add("default", new XrdProofGroup("default"));
      return fGroups.Num();;
   }

   // Did the file changed ?
   if (fCfgFile.fName != fn) {
      fCfgFile.fName = fn;
      XrdProofdAux::Expand(fCfgFile.fName);
      fCfgFile.fMtime = 0;
   }

   // Get the modification time
   struct stat st;
   if (stat(fCfgFile.fName.c_str(), &st) != 0)
      return -1;
   TRACE(DBG, "Config: enter: time of last modification: " << st.st_mtime);

   // File should be loaded only once
   if (st.st_mtime <= fCfgFile.fMtime)
      return 0;

   // Save the modification time
   fCfgFile.fMtime = st.st_mtime;

   // Open the defined path.
   FILE *fin = 0;
   if (!(fin = fopen(fCfgFile.fName.c_str(), "r"))) {
      TRACE(XERR, "Config: cannot open file: "<<fCfgFile.fName<<" (errno:"<<errno<<")");
      return -1;
   }

   // This part must be modified in atomic way
   XrdOucMutexHelper mhp(fMutex);

   // Reset existing info
   fGroups.Purge();

   // Create "default" group
   fGroups.Add("default", new XrdProofGroup("default"));

   // Read now the directives
   char lin[2048];
   while (fgets(lin,sizeof(lin),fin)) {
      // Remove trailing '\n'
      if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
      // Skip comments or empty lines
      if (lin[0] == '#' || strlen(lin) <= 0) continue;
      // Good line: parse it
      bool gotkey = 0, gotgrp = 0;
      XrdOucString gl(lin), tok, key, group;
      gl.replace(" ",",");
      int from = 0;
      while ((from = gl.tokenize(tok, from, ',')) != -1) {
         if (tok.length() > 0) {
            if (!gotkey) {
               key = tok;
               gotkey = 1;
            } else if (!gotgrp) {
               group = tok;
               gotgrp = 1;
               break;
            }
         }
      }
      // Check consistency
      if (!gotkey || !gotgrp) {
         // Insufficient info
         TRACE(DBG, "Config: incomplete line: " << lin);
         continue;
      }

      // Get linked to the group, if any
      XrdProofGroup *g = fGroups.Find(group.c_str());

      // Action depends on key
      if (key == "group") {
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0)
               // Add group member
               g->AddMember(tok.c_str());
         }
      } else if (key == "property") {
         // Property definition: format of property is
         // property <group> <property_name> <nominal_value> [<effective_value>]
         XrdOucString name;
         int nom;
         bool gotname = 0, gotnom = 0;
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0) {
               if (!gotname) {
                  name = tok;
                  gotname= 1;
               } else if (!gotnom) {
                  nom = atoi(tok.c_str());
                  gotnom = 1;
                  break;
               }
            }
         }
         if (!gotname || !gotnom) {
            // Insufficient info
            TRACE(DBG, "Config: incomplete property line: " << lin);
            continue;
         }
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         if (name == "priority")
            g->SetPriority(nom);
         if (name == "fraction")
            g->SetFraction(nom);
      }
   }

   // Return the number of active groups
   return fGroups.Num();
}

<commit_msg><commit_after>// @(#)root/proofd:$Name:  $:$Id: XrdProofGroup.cxx,v 1.2 2007/06/21 07:41:06 ganis Exp $
// Author: Gerardo Ganis  June 2007

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// XrdProofGroup                                                        //
//                                                                      //
// Authors: G. Ganis, CERN, 2007                                        //
//                                                                      //
// Class describing groups                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////
#include "XrdProofdPlatform.h"

#include "XrdProofGroup.h"
#include "XrdProofdTrace.h"

static const char *gTraceID = " ";
extern XrdOucTrace *XrdProofdTrace;

// Local definitions
#define TRACEID gTraceID

// Functions used in scanning hash tables

//__________________________________________________________________________
static int CheckUser(const char *, XrdProofGroup *g, void *u)
{
   // Check if user 'u' is memmebr of group 'grp'

   const char *usr = (const char *)u;

   if (g && usr && g->HasMember(usr))
      // Found the group
      return 1;

   // Check next
   return 0;
}

//__________________________________________________________________________
static int ExportGroup(const char *, XrdProofGroup *g, void *u)
{
   // Add a string describing group 'g' to a global string

   XrdOucString *msg = (XrdOucString *)u;

   if (msg->length() > 0)
      *msg += '\n';

   *msg = g->Name(); *msg += ": ";
   *msg += ", size: ";
   *msg += g->Size();
   *msg += ", members(s): ";
   *msg += g->Members();

   return 0;
}

//__________________________________________________________________________
static int PrintGroup(const char *, XrdProofGroup *g, void *)
{
   // Print info describing group 'g' to stdout

   if (g)
      g->Print();

   return 0;
}

//__________________________________________________________________________
static int AuxFunc(const char *, XrdProofGroup *g, void *s)
{
   // Generic function used for auxiliary purpose

   XrdOucString *opt = (XrdOucString *)s;

   if (!opt || opt->length() <= 0 || (*opt) == "getfirst")
      // Stop going through the table
      return 1;

   if (opt->beginswith("getnextgrp:")) {
      XrdOucString grp("||");
      grp.insert(g->Name(),1);
      if (opt->find(grp) == STR_NPOS) {
         *opt += grp;
         return 1;
      }
   }

   // Process next
   return 0;
}

//__________________________________________________________________________
XrdProofGroup::XrdProofGroup(const char *n, const char *m)
              : fName(n), fMembers(m)
{
   // Constructor

   fSize = 0;
   fActive = 0;
   fPriority = -1;
   fFraction = -1;
   fFracEff = 0;
   fMutex = new XrdOucRecMutex;
}
//__________________________________________________________________________
XrdProofGroup::~XrdProofGroup()
{
   // Destructor

   if (fMutex)
      delete fMutex;
   fMutex = 0;
}

//__________________________________________________________________________
void XrdProofGroup::Print()
{
   // Dump group content

   XrdOucMutexHelper mhp(fMutex);

   if (fName != "default") {
      XPDPRT("+++ Group: "<<fName<<", size "<<fSize<<" member(s) ("<<fMembers<<")");
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   } else {
      XPDPRT("+++ Group: "<<fName);
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   }
}

//__________________________________________________________________________
void XrdProofGroup::Count(const char *usr, int n)
{
   // Modify the active count

   // A username must be defined and an action required
   if (!usr || strlen(usr) == 0 || n == 0)
      return;

   // Reference string
   XrdOucString u(usr);
   u += ",";

   XrdOucMutexHelper mhp(fMutex);

   // If we are named, the user must be a member
   if (fName != "unnamed" && fMembers.find(u) == STR_NPOS)
      return;

   if (n > 0) {

      // Don't count it if already done
      if (fActives.find(u) != STR_NPOS)
         return;

      fActives += u;

   } else {

      // Don't remove it if not active
      if (fActives.find(u) == STR_NPOS)
         return;

      fActives.replace(u,"");
   }

   // Count
   fActive += n;
}

//__________________________________________________________________________
bool XrdProofGroup::HasMember(const char *usr)
{
   // Check if 'usr' is member of this group

   XrdOucMutexHelper mhp(fMutex);
   XrdOucString u(usr); u += ",";
   int iu = fMembers.find(u);
   if (iu != STR_NPOS)
      if (iu == 0 || fMembers[iu-1] == ',')
         return 1;
   return 0;
}

//__________________________________________________________________________
XrdProofGroupMgr::XrdProofGroupMgr(const char *fn)
{
   // Constructor

   ResetIter();
   Config(fn);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Apply(int (*f)(const char *, XrdProofGroup *,
                                                void *), void *arg)
{
   // Apply function 'f' to the hash table of groups; 'arg' is passed to 'f'
   // in the last argument. After applying 'f', the action depends on the
   // return value with the following rule:
   //         < 0 - the hash table item is deleted.
   //         = 0 - the next hash table item is processed.
   //         > 0 - processing stops and the hash table item is returned.

   return (fGroups.Num() > 0 ? fGroups.Apply(f,arg) : (XrdProofGroup *)0);
}

//__________________________________________________________________________
XrdOucString XrdProofGroupMgr::Export(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   XrdOucString msg;

   if (!grp) {
      fGroups.Apply(ExportGroup, (void *) &msg);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      ExportGroup(grp, g, (void *) &msg);
   }

   return msg;
}

//__________________________________________________________________________
void XrdProofGroupMgr::Print(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   if (!grp) {
      fGroups.Apply(PrintGroup, 0);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      PrintGroup(grp, g, 0);
   }

   return;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetGroup(const char *grp)
{
   // Returns the instance of for group 'grp.
   // Return 0 in the case the group does not exist

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0)
      return fGroups.Find(grp);
   return (XrdProofGroup *)0;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetUserGroup(const char *usr, const char *grp)
{
   // Returns the instance of the first group to which this user belongs;
   // if grp != 0, return the instance corresponding to group 'grp', if
   // existing and the // user belongs to it.
   // Return 0 in the case the user does not belong to any group or does not
   // belong to 'grp'.

   XrdProofGroup *g = 0;

   // Check inputs
   if (!usr || strlen(usr) <= 0)
      return g;

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0) {
      g = fGroups.Find(grp);
      if (g && g->HasMember(usr))
         return g;
      else
         return (XrdProofGroup *)0;
   }

   // Scan the table
   g = fGroups.Apply(CheckUser, (void *)usr);

   // Assign to "default" group if nothing was found
   return ((!g) ? fGroups.Find("default") : g);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Next()
{
   // Returns the instance of next group in the pseudo-iterator
   // functionality. To scan over all the groups do the following:
   //         ResetIter();
   //         while ((g = Next())) {
   //            // ... Process group
   //         }
   // Return 0 when there are no more groups

   return fGroups.Apply(AuxFunc,&fIterator);
}

//__________________________________________________________________________
int XrdProofGroupMgr::Config(const char *fn)
{
   // (Ri-)configure the group info using the file 'fn'.
   // Return the number of active groups or -1 in case of error.

   if (!fn || strlen(fn) <= 0) {
      // This call is to reset existing info and remain with
      // the 'default' group only
      XrdOucMutexHelper mhp(fMutex);
      // Reset existing info
      fGroups.Purge();
      // Create "default" group
      fGroups.Add("default", new XrdProofGroup("default"));
      return fGroups.Num();;
   }

   // Did the file changed ?
   if (fCfgFile.fName != fn) {
      fCfgFile.fName = fn;
      XrdProofdAux::Expand(fCfgFile.fName);
      fCfgFile.fMtime = 0;
   }

   // Get the modification time
   struct stat st;
   if (stat(fCfgFile.fName.c_str(), &st) != 0)
      return -1;
   TRACE(DBG, "Config: enter: time of last modification: " << st.st_mtime);

   // File should be loaded only once
   if (st.st_mtime <= fCfgFile.fMtime)
      return 0;

   // Save the modification time
   fCfgFile.fMtime = st.st_mtime;

   // Open the defined path.
   FILE *fin = 0;
   if (!(fin = fopen(fCfgFile.fName.c_str(), "r"))) {
      TRACE(XERR, "Config: cannot open file: "<<fCfgFile.fName<<" (errno:"<<errno<<")");
      return -1;
   }

   // This part must be modified in atomic way
   XrdOucMutexHelper mhp(fMutex);

   // Reset existing info
   fGroups.Purge();

   // Create "default" group
   fGroups.Add("default", new XrdProofGroup("default"));

   // Read now the directives
   char lin[2048];
   while (fgets(lin,sizeof(lin),fin)) {
      // Remove trailing '\n'
      if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
      // Skip comments or empty lines
      if (lin[0] == '#' || strlen(lin) <= 0) continue;
      // Good line: parse it
      bool gotkey = 0, gotgrp = 0;
      XrdOucString gl(lin), tok, key, group;
      gl.replace(" ",",");
      int from = 0;
      while ((from = gl.tokenize(tok, from, ',')) != -1) {
         if (tok.length() > 0) {
            if (!gotkey) {
               key = tok;
               gotkey = 1;
            } else if (!gotgrp) {
               group = tok;
               gotgrp = 1;
               break;
            }
         }
      }
      // Check consistency
      if (!gotkey || !gotgrp) {
         // Insufficient info
         TRACE(DBG, "Config: incomplete line: " << lin);
         continue;
      }

      // Get linked to the group, if any
      XrdProofGroup *g = fGroups.Find(group.c_str());

      // Action depends on key
      if (key == "group") {
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0)
               // Add group member
               g->AddMember(tok.c_str());
         }
      } else if (key == "property") {
         // Property definition: format of property is
         // property <group> <property_name> <nominal_value> [<effective_value>]
         XrdOucString name;
         int nom;
         bool gotname = 0, gotnom = 0;
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0) {
               if (!gotname) {
                  name = tok;
                  gotname= 1;
               } else if (!gotnom) {
                  nom = atoi(tok.c_str());
                  gotnom = 1;
                  break;
               }
            }
         }
         if (!gotname || !gotnom) {
            // Insufficient info
            TRACE(DBG, "Config: incomplete property line: " << lin);
            continue;
         }
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         if (name == "priority")
            g->SetPriority(nom);
         if (name == "fraction")
            g->SetFraction(nom);
      }
   }

   // Return the number of active groups
   return fGroups.Num();
}

<|endoftext|>


<commit_before>// @(#)root/proofd:$Name:  $:$Id: XrdProofGroup.cxx,v 1.3 2007/06/21 10:46:09 ganis Exp $
// Author: Gerardo Ganis  June 2007

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// XrdProofGroup                                                        //
//                                                                      //
// Authors: G. Ganis, CERN, 2007                                        //
//                                                                      //
// Class describing groups                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////
#include "XrdProofdPlatform.h"

#include "XrdProofGroup.h"
#include "XrdProofdTrace.h"

static const char *gTraceID = " ";
extern XrdOucTrace *XrdProofdTrace;

// Local definitions
#define TRACEID gTraceID

// Functions used in scanning hash tables

//__________________________________________________________________________
static int CheckUser(const char *, XrdProofGroup *g, void *u)
{
   // Check if user 'u' is memmebr of group 'grp'

   const char *usr = (const char *)u;

   if (g && usr && g->HasMember(usr))
      // Found the group
      return 1;

   // Check next
   return 0;
}

//__________________________________________________________________________
static int ExportGroup(const char *, XrdProofGroup *g, void *u)
{
   // Add a string describing group 'g' to a global string

   XrdOucString *msg = (XrdOucString *)u;

   if (msg->length() > 0)
      *msg += '\n';

   *msg = g->Name(); *msg += ": ";
   *msg += ", size: ";
   *msg += g->Size();
   *msg += ", members(s): ";
   *msg += g->Members();

   return 0;
}

//__________________________________________________________________________
static int PrintGroup(const char *, XrdProofGroup *g, void *)
{
   // Print info describing group 'g' to stdout

   if (g)
      g->Print();

   return 0;
}

//__________________________________________________________________________
static int AuxFunc(const char *, XrdProofGroup *g, void *s)
{
   // Generic function used for auxiliary purpose

   XrdOucString *opt = (XrdOucString *)s;

   if (!opt || opt->length() <= 0 || (*opt) == "getfirst")
      // Stop going through the table
      return 1;

   if (opt->beginswith("getnextgrp:")) {
      XrdOucString grp("||");
      grp.insert(g->Name(),1);
      if (opt->find(grp) == STR_NPOS) {
         *opt += grp;
         return 1;
      }
   }

   // Process next
   return 0;
}

//__________________________________________________________________________
XrdProofGroup::XrdProofGroup(const char *n, const char *m)
              : fName(n), fMembers(m)
{
   // Constructor

   fSize = 0;
   fActive = 0;
   fPriority = -1;
   fFraction = -1;
   fFracEff = 0;
   fMutex = new XrdOucRecMutex;
}
//__________________________________________________________________________
XrdProofGroup::~XrdProofGroup()
{
   // Destructor

   if (fMutex)
      delete fMutex;
   fMutex = 0;
}

//__________________________________________________________________________
void XrdProofGroup::Print()
{
   // Dump group content

   XrdOucMutexHelper mhp(fMutex);

   if (fName != "default") {
      XPDPRT("+++ Group: "<<fName<<", size "<<fSize<<" member(s) ("<<fMembers<<")");
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   } else {
      XPDPRT("+++ Group: "<<fName);
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   }
}

//__________________________________________________________________________
void XrdProofGroup::Count(const char *usr, int n)
{
   // Modify the active count

   // A username must be defined and an action required
   if (!usr || strlen(usr) == 0 || n == 0)
      return;

   // Reference string
   XrdOucString u(usr);
   u += ",";

   XrdOucMutexHelper mhp(fMutex);

   // If we are named, the user must be a member
   if (fName != "unnamed" && fMembers.find(u) == STR_NPOS)
      return;

   if (n > 0) {

      // Don't count it if already done
      if (fActives.find(u) != STR_NPOS)
         return;

      fActives += u;

   } else {

      // Don't remove it if not active
      if (fActives.find(u) == STR_NPOS)
         return;

      fActives.replace(u,"");
   }

   // Count
   fActive += n;
}

//__________________________________________________________________________
bool XrdProofGroup::HasMember(const char *usr)
{
   // Check if 'usr' is member of this group

   XrdOucMutexHelper mhp(fMutex);
   XrdOucString u(usr); u += ",";
   int iu = fMembers.find(u);
   if (iu != STR_NPOS)
      if (iu == 0 || fMembers[iu-1] == ',')
         return 1;
   return 0;
}

//__________________________________________________________________________
XrdProofGroupMgr::XrdProofGroupMgr(const char *fn)
{
   // Constructor

   ResetIter();
   Config(fn);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Apply(int (*f)(const char *, XrdProofGroup *,
                                                void *), void *arg)
{
   // Apply function 'f' to the hash table of groups; 'arg' is passed to 'f'
   // in the last argument. After applying 'f', the action depends on the
   // return value with the following rule:
   //         < 0 - the hash table item is deleted.
   //         = 0 - the next hash table item is processed.
   //         > 0 - processing stops and the hash table item is returned.

   return (fGroups.Num() > 0 ? fGroups.Apply(f,arg) : (XrdProofGroup *)0);
}

//__________________________________________________________________________
XrdOucString XrdProofGroupMgr::Export(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   XrdOucString msg;

   if (!grp) {
      fGroups.Apply(ExportGroup, (void *) &msg);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      ExportGroup(grp, g, (void *) &msg);
   }

   return msg;
}

//__________________________________________________________________________
void XrdProofGroupMgr::Print(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   if (!grp) {
      fGroups.Apply(PrintGroup, 0);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      PrintGroup(grp, g, 0);
   }

   return;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetGroup(const char *grp)
{
   // Returns the instance of for group 'grp.
   // Return 0 in the case the group does not exist

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0)
      return fGroups.Find(grp);
   return (XrdProofGroup *)0;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetUserGroup(const char *usr, const char *grp)
{
   // Returns the instance of the first group to which this user belongs;
   // if grp != 0, return the instance corresponding to group 'grp', if
   // existing and the // user belongs to it.
   // Return 0 in the case the user does not belong to any group or does not
   // belong to 'grp'.

   XrdProofGroup *g = 0;

   // Check inputs
   if (!usr || strlen(usr) <= 0)
      return g;

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0) {
      g = fGroups.Find(grp);
      if (g && g->HasMember(usr))
         return g;
      else
         return (XrdProofGroup *)0;
   }

   // Scan the table
   g = fGroups.Apply(CheckUser, (void *)usr);

   // Assign to "default" group if nothing was found
   return ((!g) ? fGroups.Find("default") : g);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Next()
{
   // Returns the instance of next group in the pseudo-iterator
   // functionality. To scan over all the groups do the following:
   //         ResetIter();
   //         while ((g = Next())) {
   //            // ... Process group
   //         }
   // Return 0 when there are no more groups

   return fGroups.Apply(AuxFunc,&fIterator);
}

//__________________________________________________________________________
int XrdProofGroupMgr::Config(const char *fn)
{
   // (Ri-)configure the group info using the file 'fn'.
   // Return the number of active groups or -1 in case of error.

   if (!fn || strlen(fn) <= 0) {
      // This call is to reset existing info and remain with
      // the 'default' group only
      XrdOucMutexHelper mhp(fMutex);
      // Reset existing info
      fGroups.Purge();
      // Create "default" group
      fGroups.Add("default", new XrdProofGroup("default"));
      return fGroups.Num();;
   }

   // Did the file changed ?
   if (fCfgFile.fName != fn) {
      fCfgFile.fName = fn;
      XrdProofdAux::Expand(fCfgFile.fName);
      fCfgFile.fMtime = 0;
   }

   // Get the modification time
   struct stat st;
   if (stat(fCfgFile.fName.c_str(), &st) != 0)
      return -1;
   TRACE(DBG, "Config: enter: time of last modification: " << st.st_mtime);

   // File should be loaded only once
   if (st.st_mtime <= fCfgFile.fMtime)
      return 0;

   // Save the modification time
   fCfgFile.fMtime = st.st_mtime;

   // Open the defined path.
   FILE *fin = 0;
   if (!(fin = fopen(fCfgFile.fName.c_str(), "r"))) {
      TRACE(XERR, "Config: cannot open file: "<<fCfgFile.fName<<" (errno:"<<errno<<")");
      return -1;
   }

   // This part must be modified in atomic way
   XrdOucMutexHelper mhp(fMutex);

   // Reset existing info
   fGroups.Purge();

   // Create "default" group
   fGroups.Add("default", new XrdProofGroup("default"));

   // Read now the directives
   char lin[2048];
   while (fgets(lin,sizeof(lin),fin)) {
      // Remove trailing '\n'
      if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
      // Skip comments or empty lines
      if (lin[0] == '#' || strlen(lin) <= 0) continue;
      // Good line: parse it
      bool gotkey = 0, gotgrp = 0;
      XrdOucString gl(lin), tok, key, group;
      gl.replace(" ",",");
      int from = 0;
      while ((from = gl.tokenize(tok, from, ',')) != -1) {
         if (tok.length() > 0) {
            if (!gotkey) {
               key = tok;
               gotkey = 1;
            } else if (!gotgrp) {
               group = tok;
               gotgrp = 1;
               break;
            }
         }
      }
      // Check consistency
      if (!gotkey || !gotgrp) {
         // Insufficient info
         TRACE(DBG, "Config: incomplete line: " << lin);
         continue;
      }

      // Get linked to the group, if any
      XrdProofGroup *g = fGroups.Find(group.c_str());

      // Action depends on key
      if (key == "group") {
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0)
               // Add group member
               g->AddMember(tok.c_str());
         }
      } else if (key == "property") {
         // Property definition: format of property is
         // property <group> <property_name> <nominal_value> [<effective_value>]
         XrdOucString name;
         int nom=0;
         bool gotname = 0, gotnom = 0;
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0) {
               if (!gotname) {
                  name = tok;
                  gotname= 1;
               } else if (!gotnom) {
                  nom = atoi(tok.c_str());
                  gotnom = 1;
                  break;
               }
            }
         }
         if (!gotname || !gotnom) {
            // Insufficient info
            TRACE(DBG, "Config: incomplete property line: " << lin);
            continue;
         }
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         if (name == "priority")
            g->SetPriority(nom);
         if (name == "fraction")
            g->SetFraction(nom);
      }
   }

   // Return the number of active groups
   return fGroups.Num();
}

<commit_msg><commit_after>// @(#)root/proofd:$Name:  $:$Id: XrdProofGroup.cxx,v 1.4 2007/06/21 17:30:21 brun Exp $
// Author: Gerardo Ganis  June 2007

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// XrdProofGroup                                                        //
//                                                                      //
// Authors: G. Ganis, CERN, 2007                                        //
//                                                                      //
// Class describing groups                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////
#include "XrdProofdPlatform.h"

#include "XrdProofGroup.h"
#include "XrdProofdTrace.h"

static const char *gTraceID = " ";
extern XrdOucTrace *XrdProofdTrace;

// Local definitions
#define TRACEID gTraceID

// Functions used in scanning hash tables

//__________________________________________________________________________
static int CheckUser(const char *, XrdProofGroup *g, void *u)
{
   // Check if user 'u' is memmebr of group 'grp'

   const char *usr = (const char *)u;

   if (g && usr && g->HasMember(usr))
      // Found the group
      return 1;

   // Check next
   return 0;
}

//__________________________________________________________________________
static int ExportGroup(const char *, XrdProofGroup *g, void *u)
{
   // Add a string describing group 'g' to a global string

   XrdOucString *msg = (XrdOucString *)u;

   if (msg->length() > 0)
      *msg += '\n';

   *msg = g->Name(); *msg += ": ";
   *msg += ", size: ";
   *msg += g->Size();
   *msg += ", members(s): ";
   *msg += g->Members();

   return 0;
}

//__________________________________________________________________________
static int PrintGroup(const char *, XrdProofGroup *g, void *)
{
   // Print info describing group 'g' to stdout

   if (g)
      g->Print();

   return 0;
}

//__________________________________________________________________________
static int AuxFunc(const char *, XrdProofGroup *g, void *s)
{
   // Generic function used for auxiliary purpose

   XrdOucString *opt = (XrdOucString *)s;

   if (!opt || opt->length() <= 0 || (*opt) == "getfirst")
      // Stop going through the table
      return 1;

   if (opt->beginswith("getnextgrp:")) {
      XrdOucString grp("||");
      grp.insert(g->Name(),1);
      if (opt->find(grp) == STR_NPOS) {
         *opt += grp;
         return 1;
      }
   }

   // Process next
   return 0;
}

//__________________________________________________________________________
XrdProofGroup::XrdProofGroup(const char *n, const char *m)
              : fName(n), fMembers(m)
{
   // Constructor

   fSize = 0;
   fActive = 0;
   fPriority = -1;
   fFraction = -1;
   fFracEff = 0;
   fMutex = new XrdOucRecMutex;
}
//__________________________________________________________________________
XrdProofGroup::~XrdProofGroup()
{
   // Destructor

   if (fMutex)
      delete fMutex;
   fMutex = 0;
}

//__________________________________________________________________________
void XrdProofGroup::Print()
{
   // Dump group content

   XrdOucMutexHelper mhp(fMutex);

   if (fName != "default") {
      XPDPRT("+++ Group: "<<fName<<", size "<<fSize<<" member(s) ("<<fMembers<<")");
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   } else {
      XPDPRT("+++ Group: "<<fName);
      XPDPRT("+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
      XPDPRT("+++ End of Group: "<<fName);
   }
}

//__________________________________________________________________________
void XrdProofGroup::Count(const char *usr, int n)
{
   // Modify the active count

   // A username must be defined and an action required
   if (!usr || strlen(usr) == 0 || n == 0)
      return;

   // Reference string
   XrdOucString u(usr);
   u += ",";

   XrdOucMutexHelper mhp(fMutex);

   // If we are named, the user must be a member
   if (fName != "unnamed" && fMembers.find(u) == STR_NPOS)
      return;

   if (n > 0) {

      // Don't count it if already done
      if (fActives.find(u) != STR_NPOS)
         return;

      fActives += u;

   } else {

      // Don't remove it if not active
      if (fActives.find(u) == STR_NPOS)
         return;

      fActives.replace(u,"");
   }

   // Count
   fActive += n;
}

//__________________________________________________________________________
bool XrdProofGroup::HasMember(const char *usr)
{
   // Check if 'usr' is member of this group

   XrdOucMutexHelper mhp(fMutex);
   XrdOucString u(usr); u += ",";
   int iu = fMembers.find(u);
   if (iu != STR_NPOS)
      if (iu == 0 || fMembers[iu-1] == ',')
         return 1;
   return 0;
}

//__________________________________________________________________________
XrdProofGroupMgr::XrdProofGroupMgr(const char *fn)
{
   // Constructor

   ResetIter();
   Config(fn);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Apply(int (*f)(const char *, XrdProofGroup *,
                                                void *), void *arg)
{
   // Apply function 'f' to the hash table of groups; 'arg' is passed to 'f'
   // in the last argument. After applying 'f', the action depends on the
   // return value with the following rule:
   //         < 0 - the hash table item is deleted.
   //         = 0 - the next hash table item is processed.
   //         > 0 - processing stops and the hash table item is returned.

   return (fGroups.Num() > 0 ? fGroups.Apply(f,arg) : (XrdProofGroup *)0);
}

//__________________________________________________________________________
XrdOucString XrdProofGroupMgr::Export(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   XrdOucString msg;

   if (!grp) {
      fGroups.Apply(ExportGroup, (void *) &msg);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      ExportGroup(grp, g, (void *) &msg);
   }

   return msg;
}

//__________________________________________________________________________
void XrdProofGroupMgr::Print(const char *grp)
{
   // Return a string describing the group

   XrdOucMutexHelper mhp(fMutex);

   if (!grp) {
      fGroups.Apply(PrintGroup, 0);
   } else {
      XrdProofGroup *g = fGroups.Find(grp);
      PrintGroup(grp, g, 0);
   }

   return;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetGroup(const char *grp)
{
   // Returns the instance of for group 'grp.
   // Return 0 in the case the group does not exist

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0)
      return fGroups.Find(grp);
   return (XrdProofGroup *)0;
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::GetUserGroup(const char *usr, const char *grp)
{
   // Returns the instance of the first group to which this user belongs;
   // if grp != 0, return the instance corresponding to group 'grp', if
   // existing and the // user belongs to it.
   // Return 0 in the case the user does not belong to any group or does not
   // belong to 'grp'.

   XrdProofGroup *g = 0;

   // Check inputs
   if (!usr || strlen(usr) <= 0)
      return g;

   // If the group is defined and exists, check it
   if (grp && strlen(grp) > 0) {
      g = fGroups.Find(grp);
      if (g && (!strncmp(g->Name(),"default",7) || g->HasMember(usr)))
         return g;
      else
         return (XrdProofGroup *)0;
   }

   // Scan the table
   g = fGroups.Apply(CheckUser, (void *)usr);

   // Assign to "default" group if nothing was found
   return ((!g) ? fGroups.Find("default") : g);
}

//__________________________________________________________________________
XrdProofGroup *XrdProofGroupMgr::Next()
{
   // Returns the instance of next group in the pseudo-iterator
   // functionality. To scan over all the groups do the following:
   //         ResetIter();
   //         while ((g = Next())) {
   //            // ... Process group
   //         }
   // Return 0 when there are no more groups

   return fGroups.Apply(AuxFunc,&fIterator);
}

//__________________________________________________________________________
int XrdProofGroupMgr::Config(const char *fn)
{
   // (Ri-)configure the group info using the file 'fn'.
   // Return the number of active groups or -1 in case of error.

   if (!fn || strlen(fn) <= 0) {
      // This call is to reset existing info and remain with
      // the 'default' group only
      XrdOucMutexHelper mhp(fMutex);
      // Reset existing info
      fGroups.Purge();
      // Create "default" group
      fGroups.Add("default", new XrdProofGroup("default"));
      return fGroups.Num();;
   }

   // Did the file changed ?
   if (fCfgFile.fName != fn) {
      fCfgFile.fName = fn;
      XrdProofdAux::Expand(fCfgFile.fName);
      fCfgFile.fMtime = 0;
   }

   // Get the modification time
   struct stat st;
   if (stat(fCfgFile.fName.c_str(), &st) != 0)
      return -1;
   TRACE(DBG, "Config: enter: time of last modification: " << st.st_mtime);

   // File should be loaded only once
   if (st.st_mtime <= fCfgFile.fMtime)
      return 0;

   // Save the modification time
   fCfgFile.fMtime = st.st_mtime;

   // Open the defined path.
   FILE *fin = 0;
   if (!(fin = fopen(fCfgFile.fName.c_str(), "r"))) {
      TRACE(XERR, "Config: cannot open file: "<<fCfgFile.fName<<" (errno:"<<errno<<")");
      return -1;
   }

   // This part must be modified in atomic way
   XrdOucMutexHelper mhp(fMutex);

   // Reset existing info
   fGroups.Purge();

   // Create "default" group
   fGroups.Add("default", new XrdProofGroup("default"));

   // Read now the directives
   char lin[2048];
   while (fgets(lin,sizeof(lin),fin)) {
      // Remove trailing '\n'
      if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
      // Skip comments or empty lines
      if (lin[0] == '#' || strlen(lin) <= 0) continue;
      // Good line: parse it
      bool gotkey = 0, gotgrp = 0;
      XrdOucString gl(lin), tok, key, group;
      gl.replace(" ",",");
      int from = 0;
      while ((from = gl.tokenize(tok, from, ',')) != -1) {
         if (tok.length() > 0) {
            if (!gotkey) {
               key = tok;
               gotkey = 1;
            } else if (!gotgrp) {
               group = tok;
               gotgrp = 1;
               break;
            }
         }
      }
      // Check consistency
      if (!gotkey || !gotgrp) {
         // Insufficient info
         TRACE(DBG, "Config: incomplete line: " << lin);
         continue;
      }

      // Get linked to the group, if any
      XrdProofGroup *g = fGroups.Find(group.c_str());

      // Action depends on key
      if (key == "group") {
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0)
               // Add group member
               g->AddMember(tok.c_str());
         }
      } else if (key == "property") {
         // Property definition: format of property is
         // property <group> <property_name> <nominal_value> [<effective_value>]
         XrdOucString name;
         int nom=0;
         bool gotname = 0, gotnom = 0;
         while ((from = gl.tokenize(tok, from, ',')) != -1) {
            if (tok.length() > 0) {
               if (!gotname) {
                  name = tok;
                  gotname= 1;
               } else if (!gotnom) {
                  nom = atoi(tok.c_str());
                  gotnom = 1;
                  break;
               }
            }
         }
         if (!gotname || !gotnom) {
            // Insufficient info
            TRACE(DBG, "Config: incomplete property line: " << lin);
            continue;
         }
         if (!g)
            // Create new group container
            fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
         if (name == "priority")
            g->SetPriority(nom);
         if (name == "fraction")
            g->SetFraction(nom);
      }
   }

   // Return the number of active groups
   return fGroups.Num();
}

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <dirent.h>

void ProcessEntity(struct dirent* entity);
void ProcessDirectory(const std::string& directory);
void ProcessFile(const std::string& file, const std::string& pid);

const std::string PROC_PATH("/proc"); // Please note: MUST END WITH '/' SEPARATOR!
const char SEPARATOR = '/';

const std::string VDSO("[vdso]");
const std::string MAPS("maps");

const std::size_t EXEC_BUFFER_SIZE = 128;

bool IsPidDir(const std::string& path, std::string& pid)
{
    if(path.empty())
    {
        return false;
    }

    std::size_t sep_pos = path.find_last_of(SEPARATOR);
    std::string maybe_pid;

    // path == 1234 OR path == /proc/1234

    if(sep_pos == std::string::npos)
    {
        maybe_pid = path;
    }
    else
    {
        maybe_pid = path.substr(sep_pos + 1);

        if(maybe_pid.empty())
        {
            return false;
        }
    }

    // Check whether the char sequence is a number.
    for(auto c = maybe_pid.begin(); c != maybe_pid.end(); ++c)
    {
        if(*c < '0' || *c > '9')
        {
            return false;
        }
    }

    pid = maybe_pid;

    return true;
}

std::string Exec(const std::string& cmd)
{
    std::vector<char> buffer;
    buffer.resize(EXEC_BUFFER_SIZE);

    std::string result;
    FILE* pipe = popen(cmd.c_str(), "r");

    if(NULL != pipe)
    {
        while(!feof(pipe))
        {
            if (fgets(&buffer.at(0), buffer.size(), pipe) != NULL)
            {
                result += &buffer.at(0);
            }
        }

        pclose(pipe);
    }

    return result;
}

void ProcessEntity(struct dirent* entity, const std::string& parent_directory)
{
    if(entity == NULL)
    {
        return;
    }

    std::string pid;
    if(entity->d_type == DT_DIR)
    {
        if(entity->d_name[0] == '.')
        {
            return;
        }

        std::string dir_name(entity->d_name);

        if(IsPidDir(dir_name, pid))
        {
            ProcessDirectory(parent_directory + SEPARATOR + dir_name);
        }
    }
    else if(entity->d_type == DT_REG)
    {
        std::string file_name(entity->d_name);
        if(file_name == MAPS)
        {
            IsPidDir(parent_directory, pid);
            ProcessFile(parent_directory + SEPARATOR + file_name, pid);
        }
    }
}

void ProcessDirectory(const std::string& directory)
{
    auto dir = opendir(directory.c_str());

    if(NULL == dir)
    {
        std::cerr << "Cannot open directory: " << directory << std::endl;
        return;
    }

    auto entity = readdir(dir);

    while(entity != NULL)
    {
        ProcessEntity(entity, directory);
        entity = readdir(dir);
    }

    closedir(dir);
}

void ProcessFile(const std::string& file, const std::string& pid)
{
    std::ifstream input(file.c_str());
    if(!input)
    {
        std::cout << "Failed to open " << file << std::endl;
        return;
    }

    std::string map_line;
    while(std::getline(input, map_line))
    {
        // Search for ...[vdso] entries.
        if(map_line.find_first_of(VDSO) != std::string::npos)
        {
            // Get process name by PID
            std::string ps_query("ps " + pid);
            std::string ps_stats = Exec(ps_query.c_str());
            std::cout << "! " << ps_stats.substr(ps_stats.find_first_of('\n') + 1);
            break;
        }
    }
}

int main(int argc, char** argv)
{
    ProcessDirectory(PROC_PATH);
    return 0;
}
<commit_msg>Minor fixes<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <dirent.h>

void ProcessEntity(struct dirent* entity);
void ProcessDirectory(const std::string& directory);
void ProcessFile(const std::string& file, const std::string& pid);

const std::string PROC_PATH("/proc");
const char SEPARATOR = '/';

const std::string VDSO("[vdso]");
const std::string MAPS("maps");

const std::size_t EXEC_BUFFER_SIZE = 128;

bool IsPidDir(const std::string& path, std::string& pid)
{
    if(path.empty())
    {
        return false;
    }

    std::size_t sep_pos = path.find_last_of(SEPARATOR);
    std::string maybe_pid;

    // path == 1234 OR path == /proc/1234

    if(sep_pos == std::string::npos)
    {
        maybe_pid = path;
    }
    else
    {
        maybe_pid = path.substr(sep_pos + 1);

        if(maybe_pid.empty())
        {
            return false;
        }
    }

    // Check whether the char sequence is a number.
    for(auto c = maybe_pid.begin(); c != maybe_pid.end(); ++c)
    {
        if(*c < '0' || *c > '9')
        {
            return false;
        }
    }

    pid = maybe_pid;

    return true;
}

std::string Exec(const std::string& cmd)
{
    std::vector<char> buffer;
    buffer.resize(EXEC_BUFFER_SIZE);

    std::string result;
    FILE* pipe = popen(cmd.c_str(), "r");

    if(NULL != pipe)
    {
        while(!feof(pipe))
        {
            if (fgets(&buffer.at(0), buffer.size(), pipe) != NULL)
            {
                result += &buffer.at(0);
            }
        }

        pclose(pipe);
    }

    return result;
}

void ProcessEntity(struct dirent* entity, const std::string& parent_directory)
{
    if(entity == NULL)
    {
        return;
    }

    std::string pid;
    if(entity->d_type == DT_DIR)
    {
        if(entity->d_name[0] == '.')
        {
            return;
        }

        std::string dir_name(entity->d_name);

        if(IsPidDir(dir_name, pid))
        {
            ProcessDirectory(parent_directory + SEPARATOR + dir_name);
        }
    }
    else if(entity->d_type == DT_REG)
    {
        std::string file_name(entity->d_name);
        if(file_name == MAPS)
        {
            IsPidDir(parent_directory, pid);
            ProcessFile(parent_directory + SEPARATOR + file_name, pid);
        }
    }
}

void ProcessDirectory(const std::string& directory)
{
    auto dir = opendir(directory.c_str());

    if(NULL == dir)
    {
        std::cerr << "Cannot open directory: " << directory << std::endl;
        return;
    }

    auto entity = readdir(dir);

    while(entity != NULL)
    {
        ProcessEntity(entity, directory);
        entity = readdir(dir);
    }

    closedir(dir);
}

void ProcessFile(const std::string& file, const std::string& pid)
{
    std::ifstream input(file.c_str());
    if(!input)
    {
        std::cerr << "Failed to open " << file << std::endl;
        return;
    }

    std::string map_line;
    while(std::getline(input, map_line))
    {
        // Search for ...[vdso] entries.
        if(map_line.find_first_of(VDSO) != std::string::npos)
        {
            // Get process name by PID
            std::string ps_query("ps " + pid);
            std::string ps_stats = Exec(ps_query.c_str());
            std::cout << "! " << ps_stats.substr(ps_stats.find_first_of('\n') + 1);
            break;
        }
    }
}

int main(int argc, char** argv)
{
    ProcessDirectory(PROC_PATH);
    return 0;
}
<|endoftext|>


<commit_before>#include "helpers.hpp"
#include <count.hpp>

#include <vector>
#include <iterator>
#include <utility>

#include "catch.hpp"

using iter::count;

TEST_CASE("count: watch for 10 elements", "[count]") {
    std::vector<int> v{};
    for (auto i : count()) {
        v.push_back(i);
        if (i == 9) break;
    }

    const std::vector<int> vc{0,1,2,3,4,5,6,7,8,9};
    REQUIRE( v == vc );
}
<commit_msg>adds count with starting value test<commit_after>#include "helpers.hpp"
#include <count.hpp>

#include <vector>
#include <iterator>
#include <utility>

#include "catch.hpp"

using iter::count;

TEST_CASE("count: watch for 10 elements", "[count]") {
    std::vector<int> v{};
    for (auto i : count()) {
        v.push_back(i);
        if (i == 9) break;
    }

    const std::vector<int> vc{0,1,2,3,4,5,6,7,8,9};
    REQUIRE( v == vc );
}

TEST_CASE("count: start at 10", "[count]") {
    std::vector<int> v{};
    for (auto i : count(10)) {
        v.push_back(i);
        if (i == 14) break;
    }

    const std::vector<int> vc{10,11,12,13,14,15};
    REQUIRE( v == vc );
}
<|endoftext|>


<commit_before>// Used for testing, do not use it as an example
#include <qpp.h>
#include <experimental/experimental.h>
// #include <MATLAB/matlab.h>
using namespace qpp;

// Future work
// TODO: Implement a circuit description language, load/save from/to file
// TODO: Write a MatrixView class, for multi-index lazy evaluation view - wip
// TODO: use assert in performance-critical functions (qpp::internal)

cmat gettmp()
{
    cmat tmp(2, 2);
    tmp << 10, 20, 30, 40;
    return tmp;
}

int main()
{
    // testing qpp::experimental::MatrixView
    idx ROWS = 4, COLS = 4;
    cmat A = gt.CNOT;
    //A << 1, 2., 3., 4.;

    std::cout << "Initial:\n";
    std::cout << disp(A) << std::endl << std::endl;

    auto viewA = experimental::make_MatrixView(A, {1, 0});
    experimental::MatrixView<cmat> viewB = viewA;

    std::cout << "MatrixView: \n";
    std::cout << disp(viewA) << std::endl << std::endl;

    std::cout << "Copy via static_cast/get() of the MatrixView:\n";
    cmat result = static_cast<cmat>(viewA); // convert
    cmat result1 = viewA.get(); // force evaluation
    std::cout << disp(result) << std::endl << std::endl;
    std::cout << disp(result1) << std::endl << std::endl;

    std::cout << "Copy MatrixView:\n";
    auto viewAcopy = viewA; // copy
    std::cout << disp(viewAcopy) << std::endl << std::endl;

    // rvalues should not bind

    // should not compile, and it doesn't :)
    // auto view_expression = experimental::make_MatrixView(A + A, {0, 1});
    // std::cout << disp(view_expression) << std::endl;

    // this line should not compile, and it doesn't :)
    // experimental::MatrixView<cmat> tmpview{gettmp(), {0, 1}};

    std::cout << "MatrixValue as a rvalue:\n";
    std::cout << disp(qpp::experimental::make_MatrixView(A, {1, 0}));
    std::cout << std::endl;
}<commit_msg>commit<commit_after>// Used for testing, do not use it as an example
#include <qpp.h>
#include <experimental/experimental.h>
// #include <MATLAB/matlab.h>
using namespace qpp;

// Future work
// TODO: Implement a circuit description language, load/save from/to file
// TODO: Write a MatrixView class, for multi-index lazy evaluation view - wip
// TODO: use assert in performance-critical functions (qpp::internal)

cmat gettmp()
{
    cmat tmp(2, 2);
    tmp << 10, 20, 30, 40;
    return tmp;
}

int main()
{
    // testing qpp::experimental::MatrixView
    idx ROWS = 4, COLS = 4;
    cmat A = gt.CNOT;
    //A << 1, 2., 3., 4.;

    std::cout << "Initial:\n";
    std::cout << disp(A) << std::endl << std::endl;

    auto viewA = experimental::make_MatrixView(A, {1, 0});
    experimental::MatrixView<cmat> viewB = viewA;

    std::cout << "MatrixView: \n";
    std::cout << disp(viewA) << std::endl << std::endl;

    std::cout << "Copy via static_cast/get() of the MatrixView:\n";
    cmat result = static_cast<cmat>(viewA); // convert
    cmat result1 = viewA.get(); // force evaluation
    std::cout << disp(result) << std::endl << std::endl;
    std::cout << disp(result1) << std::endl << std::endl;

    std::cout << "Copy MatrixView:\n";
    auto viewAcopy = viewA; // copy
    std::cout << disp(viewAcopy) << std::endl << std::endl;

    // rvalues should not bind

    // should not compile, and it doesn't :)
    // auto view_expression = experimental::make_MatrixView(A + A, {0, 1});
    // std::cout << disp(view_expression) << std::endl;

    // this line should not compile, and it doesn't :)
    // experimental::MatrixView<cmat> tmpview{gettmp(), {0, 1}};

    std::cout << "MatrixValue as a rvalue:\n";
    std::cout << disp(qpp::experimental::make_MatrixView(A, {1, 0}));
    std::cout << std::endl;

    std::cout << "Testing MatrixView via syspermute:\n";
    std::vector<idx> subsys{1, 2, 3, 7, 4, 6, 5, 0};
    idx N = std::pow(2, subsys.size());
    cmat rho = qpp::rand<cmat>(256, 256);
    cmat B = syspermute(rho, subsys);
    cmat C = experimental::make_MatrixView(rho, invperm(subsys)).get();
    std::cout << "Norm difference: " << norm(B - C) << std::endl;
}<|endoftext|>


<commit_before>#include <ruby.h>

#include "leveldb/db.h"
#include "leveldb/write_batch.h"

static VALUE m_leveldb;
static VALUE c_db;
static VALUE c_error;

// support 1.9 and 1.8
#ifndef RSTRING_PTR
#define RSTRING_PTR(v) RSTRING(v)->ptr
#endif

// convert status errors into exceptions
#define RAISE_ON_ERROR(status) do { \
  if(!status.ok()) { \
    VALUE exc = rb_exc_new2(c_error, status.ToString().c_str()); \
    rb_exc_raise(exc); \
  }  \
} while(0)

typedef struct bound_db {
  leveldb::DB* db;
} bound_db;

static void db_free(bound_db* db) {
  delete db->db;
}

static VALUE db_make(VALUE klass, VALUE v_pathname, VALUE v_create_if_necessary, VALUE v_break_if_exists) {
  Check_Type(v_pathname, T_STRING);

  bound_db* db = new bound_db;
  char* pathname_c = RSTRING_PTR(v_pathname);
  std::string pathname = std::string((char*)RSTRING_PTR(v_pathname));

  leveldb::Options options;
  if(RTEST(v_create_if_necessary)) options.create_if_missing = true;
  if(RTEST(v_break_if_exists)) options.error_if_exists = true;
  leveldb::Status status = leveldb::DB::Open(options, pathname, &db->db);
  RAISE_ON_ERROR(status);

  VALUE o_db = Data_Wrap_Struct(klass, NULL, db_free, db);
  VALUE argv[1] = { v_pathname };
  rb_obj_call_init(o_db, 1, argv);

  return o_db;
}

static VALUE db_close(VALUE self) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  db_free(db);
  return Qtrue;
}

static VALUE db_get(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  std::string key = std::string((char*)RSTRING_PTR(v_key));
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);
  if(status.IsNotFound()) return Qnil;

  RAISE_ON_ERROR(status);
  return rb_str_new2(value.c_str());
}

static VALUE db_delete(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  std::string key = std::string((char*)RSTRING_PTR(v_key));
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);

  if(status.IsNotFound()) return Qnil;

  status = db->db->Delete(leveldb::WriteOptions(), key);
  RAISE_ON_ERROR(status);

  return rb_str_new2(value.c_str());
}

static VALUE db_exists(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  std::string key = std::string((char*)RSTRING_PTR(v_key));
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);

  if(status.IsNotFound()) return Qfalse;
  return Qtrue;
}

static VALUE db_put(VALUE self, VALUE v_key, VALUE v_value) {
  Check_Type(v_key, T_STRING);
  Check_Type(v_value, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  std::string key = std::string((char*)RSTRING_PTR(v_key));
  std::string value = std::string((char*)RSTRING_PTR(v_value));

  leveldb::Status status = db->db->Put(leveldb::WriteOptions(), key, value);

  RAISE_ON_ERROR(status);

  return v_value;
}

static VALUE db_size(VALUE self) {
  long count = 0;

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::Iterator* it = db->db->NewIterator(leveldb::ReadOptions());

  // apparently this is how we have to do it. slow and painful!
  for (it->SeekToFirst(); it->Valid(); it->Next()) count++;
  RAISE_ON_ERROR(it->status());
  delete it;
  return INT2NUM(count);
}

static VALUE db_each(VALUE self) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::Iterator* it = db->db->NewIterator(leveldb::ReadOptions());

  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    VALUE key = rb_str_new2(it->key().ToString().c_str());
    VALUE value = rb_str_new2(it->value().ToString().c_str());
    VALUE ary = rb_ary_new2(2);
    rb_ary_push(ary, key);
    rb_ary_push(ary, value);
    rb_yield(ary);
  }

  RAISE_ON_ERROR(it->status());
  delete it;

  return self;
}

static VALUE db_init(VALUE self, VALUE v_pathname) {
  rb_iv_set(self, "@pathname", v_pathname);
  return self;
}

extern "C" {
void Init_leveldb() {
  VALUE m_leveldb;

  m_leveldb = rb_define_module("LevelDB");

  c_db = rb_define_class_under(m_leveldb, "DB", rb_cObject);
  rb_define_singleton_method(c_db, "make", (VALUE (*)(...))db_make, 3);
  rb_define_method(c_db, "initialize", (VALUE (*)(...))db_init, 1);
  rb_define_method(c_db, "get", (VALUE (*)(...))db_get, 1);
  rb_define_method(c_db, "delete", (VALUE (*)(...))db_delete, 1);
  rb_define_method(c_db, "put", (VALUE (*)(...))db_put, 2);
  rb_define_method(c_db, "exists?", (VALUE (*)(...))db_exists, 1);
  rb_define_method(c_db, "close", (VALUE (*)(...))db_close, 0);
  rb_define_method(c_db, "size", (VALUE (*)(...))db_size, 0);
  rb_define_method(c_db, "each", (VALUE (*)(...))db_each, 0);

  c_error = rb_define_class_under(m_leveldb, "Error", rb_eStandardError);
}
}
<commit_msg>allow for zero-bytes in keys and values<commit_after>#include <ruby.h>

#include "leveldb/db.h"
#include "leveldb/slice.h"

static VALUE m_leveldb;
static VALUE c_db;
static VALUE c_error;

// support 1.9 and 1.8
#ifndef RSTRING_PTR
#define RSTRING_PTR(v) RSTRING(v)->ptr
#endif

// convert status errors into exceptions
#define RAISE_ON_ERROR(status) do { \
  if(!status.ok()) { \
    VALUE exc = rb_exc_new2(c_error, status.ToString().c_str()); \
    rb_exc_raise(exc); \
  }  \
} while(0)

typedef struct bound_db {
  leveldb::DB* db;
} bound_db;

static void db_free(bound_db* db) {
  delete db->db;
}

static VALUE db_make(VALUE klass, VALUE v_pathname, VALUE v_create_if_necessary, VALUE v_break_if_exists) {
  Check_Type(v_pathname, T_STRING);

  bound_db* db = new bound_db;
  char* pathname_c = RSTRING_PTR(v_pathname);
  std::string pathname = std::string((char*)RSTRING_PTR(v_pathname));

  leveldb::Options options;
  if(RTEST(v_create_if_necessary)) options.create_if_missing = true;
  if(RTEST(v_break_if_exists)) options.error_if_exists = true;
  leveldb::Status status = leveldb::DB::Open(options, pathname, &db->db);
  RAISE_ON_ERROR(status);

  VALUE o_db = Data_Wrap_Struct(klass, NULL, db_free, db);
  VALUE argv[1] = { v_pathname };
  rb_obj_call_init(o_db, 1, argv);

  return o_db;
}

static VALUE db_close(VALUE self) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  db_free(db);
  return Qtrue;
}

#define RUBY_STRING_TO_SLICE(x) leveldb::Slice(RSTRING_PTR(x), RSTRING_LEN(x))
#define SLICE_TO_RUBY_STRING(x) rb_str_new(x.data(), x.size())
#define STRING_TO_RUBY_STRING(x) rb_str_new(x.data(), x.size())
static VALUE db_get(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);
  if(status.IsNotFound()) return Qnil;

  RAISE_ON_ERROR(status);
  return STRING_TO_RUBY_STRING(value);
}

static VALUE db_delete(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);

  if(status.IsNotFound()) return Qnil;

  status = db->db->Delete(leveldb::WriteOptions(), key);
  RAISE_ON_ERROR(status);

  return STRING_TO_RUBY_STRING(value);
}

static VALUE db_exists(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);

  if(status.IsNotFound()) return Qfalse;
  return Qtrue;
}

static VALUE db_put(VALUE self, VALUE v_key, VALUE v_value) {
  Check_Type(v_key, T_STRING);
  Check_Type(v_value, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  leveldb::Slice value = RUBY_STRING_TO_SLICE(v_value);
  leveldb::Status status = db->db->Put(leveldb::WriteOptions(), key, value);

  RAISE_ON_ERROR(status);

  return v_value;
}

static VALUE db_size(VALUE self) {
  long count = 0;

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::Iterator* it = db->db->NewIterator(leveldb::ReadOptions());

  // apparently this is how we have to do it. slow and painful!
  for (it->SeekToFirst(); it->Valid(); it->Next()) count++;
  RAISE_ON_ERROR(it->status());
  delete it;
  return INT2NUM(count);
}

static VALUE db_each(VALUE self) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::Iterator* it = db->db->NewIterator(leveldb::ReadOptions());

  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    VALUE key = SLICE_TO_RUBY_STRING(it->key());
    VALUE value = SLICE_TO_RUBY_STRING(it->value());
    VALUE ary = rb_ary_new2(2);
    rb_ary_push(ary, key);
    rb_ary_push(ary, value);
    rb_yield(ary);
  }

  RAISE_ON_ERROR(it->status());
  delete it;

  return self;
}

static VALUE db_init(VALUE self, VALUE v_pathname) {
  rb_iv_set(self, "@pathname", v_pathname);
  return self;
}

extern "C" {
void Init_leveldb() {
  VALUE m_leveldb;

  m_leveldb = rb_define_module("LevelDB");

  c_db = rb_define_class_under(m_leveldb, "DB", rb_cObject);
  rb_define_singleton_method(c_db, "make", (VALUE (*)(...))db_make, 3);
  rb_define_method(c_db, "initialize", (VALUE (*)(...))db_init, 1);
  rb_define_method(c_db, "get", (VALUE (*)(...))db_get, 1);
  rb_define_method(c_db, "delete", (VALUE (*)(...))db_delete, 1);
  rb_define_method(c_db, "put", (VALUE (*)(...))db_put, 2);
  rb_define_method(c_db, "exists?", (VALUE (*)(...))db_exists, 1);
  rb_define_method(c_db, "close", (VALUE (*)(...))db_close, 0);
  rb_define_method(c_db, "size", (VALUE (*)(...))db_size, 0);
  rb_define_method(c_db, "each", (VALUE (*)(...))db_each, 0);

  c_error = rb_define_class_under(m_leveldb, "Error", rb_eStandardError);
}
}
<|endoftext|>